Salome HOME
#18835 Automatically create groups on Geometry in SMESH when the SHAPER result is...
[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     int how = ( isBreakLink || !sameTopology ) ? IS_BREAK_LINK : MAIN_TRANSFORMED;
2426     TopoDS_Shape newShape = newGroupShape( *data, how );
2427     if ( !newShape.IsNull() )
2428     {
2429       if ( meshDS->ShapeToIndex( newShape ) > 0 ) // a group reduced to one sub-shape
2430       {
2431         TopoDS_Compound compound;
2432         BRep_Builder().MakeCompound( compound );
2433         BRep_Builder().Add( compound, newShape );
2434         newShape = compound;
2435       }
2436       int newID = _impl->GetSubMesh( newShape )->GetId();
2437       if ( oldID && oldID != newID )
2438         old2newIDs.insert( std::make_pair( oldID, newID ));
2439     }
2440   }
2441
2442   // re-assign hypotheses
2443   for ( size_t i = 0; i < ids2Hyps.size(); ++i )
2444   {
2445     int sID = ids2Hyps[i].first;
2446     std::map< int, int >::iterator o2n = old2newIDs.find( sID );
2447     if ( o2n != old2newIDs.end() )
2448       sID = o2n->second;
2449     else if ( sID != 1 )
2450       continue;
2451     const TopoDS_Shape& s = meshDS->IndexToShape( sID );
2452     const THypList&  hyps = ids2Hyps[i].second;
2453     THypList::const_iterator h = hyps.begin();
2454     for ( ; h != hyps.end(); ++h )
2455       _impl->AddHypothesis( s, (*h)->GetID() );
2456   }
2457
2458   {
2459     // restore groups on geometry
2460     for ( size_t i = 0; i < groupsData.size(); ++i )
2461     {
2462       const TGroupOnGeomData& data = groupsData[i];
2463       if ( data._shape.IsNull() )
2464         continue;
2465
2466       std::map<int, SMESH::SMESH_GroupBase_ptr>::iterator i2g = _mapGroups.find( data._oldID );
2467       if ( i2g == _mapGroups.end() ) continue;
2468
2469       SMESH_GroupBase_i* gr_i = SMESH::DownCast<SMESH_GroupBase_i*>( i2g->second );
2470       if ( !gr_i ) continue;
2471
2472       SMESH_Group* g = _impl->AddGroup( data._type, data._name.c_str(), data._oldID, data._shape );
2473       if ( !g )
2474         _mapGroups.erase( i2g );
2475       else
2476         g->GetGroupDS()->SetColor( data._color );
2477     }
2478
2479     std::map< int, int >::iterator o2n = old2newIDs.begin();
2480     for ( ; o2n != old2newIDs.end(); ++o2n )
2481     {
2482       int newID = o2n->second, oldID = o2n->first;
2483       if ( !_mapSubMesh.count( oldID ))
2484         continue;
2485       if ( newID > 0 )
2486       {
2487         _mapSubMesh   [ newID ] = _impl->GetSubMeshContaining( newID );
2488         _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
2489         _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
2490       }
2491       _mapSubMesh.   erase(oldID);
2492       _mapSubMesh_i. erase(oldID);
2493       _mapSubMeshIor.erase(oldID);
2494       if ( newID > 0 )
2495         _mapSubMesh_i [ newID ]->changeLocalId( newID );
2496     }
2497
2498     // update _mapSubMesh
2499     std::map<int, ::SMESH_subMesh*>::iterator i_sm = _mapSubMesh.begin();
2500     for ( ; i_sm != _mapSubMesh.end(); ++i_sm )
2501       i_sm->second = _impl->GetSubMesh( meshDS->IndexToShape( i_sm->first ));
2502   }
2503
2504   if ( !sameTopology )
2505   {
2506     // remove invalid study sub-objects
2507     CheckGeomGroupModif();
2508   }
2509
2510   _gen_i->UpdateIcons( me );
2511
2512   if ( !isBreakLink && isShaper )
2513   {
2514     SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( me );
2515     if ( !meshSO->_is_nil() )
2516       _gen_i->SetPixMap(meshSO, "ICON_SMESH_TREE_GEOM_MODIF");
2517   }
2518 }
2519
2520 //=============================================================================
2521 /*!
2522  * \brief Update objects depending on changed geom groups
2523  *
2524  * NPAL16168: geometrical group edition from a submesh don't modify mesh computation
2525  * issue 0020210: Update of a smesh group after modification of the associated geom group
2526  */
2527 //=============================================================================
2528
2529 void SMESH_Mesh_i::CheckGeomGroupModif()
2530 {
2531   // remove sub-meshes referring a removed sub-shapes (if main shape still exists)
2532   SALOMEDS::StudyBuilder_var builder = _gen_i->getStudyServant()->NewBuilder();
2533   GEOM::GEOM_Object_var  mainGO = GetShapeToMesh();
2534   SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( SMESH::SMESH_Mesh_var( _this() ));
2535   if ( !mainGO->_is_nil() && !meshSO->_is_nil() )
2536   {
2537     SALOMEDS::SObject_wrap rootSO, geomRefSO, geomSO;
2538     for ( CORBA::Long tag = SMESH::Tag_FirstSubMesh; tag <= SMESH::Tag_LastSubMesh; ++tag )
2539       if ( meshSO->FindSubObject( tag, rootSO.inout() ))
2540       {
2541         int nbValid = 0, nbRemoved = 0;
2542         SALOMEDS::ChildIterator_wrap chItr = _gen_i->getStudyServant()->NewChildIterator( rootSO );
2543         for ( ; chItr->More(); chItr->Next() )
2544         {
2545           SALOMEDS::SObject_wrap smSO = chItr->Value(); // sub-mesh SO
2546           if ( !smSO->_is_nil() &&
2547                smSO->FindSubObject( SMESH::Tag_RefOnShape, geomRefSO.inout() ) &&
2548                geomRefSO->ReferencedObject( geomSO.inout() )) // find geometry by reference
2549           {
2550             CORBA::Object_var  geomObj = _gen_i->SObjectToObject( geomSO );
2551             GEOM::GEOM_Object_var geom = GEOM::GEOM_Object::_narrow( geomObj );
2552             if ( !geom->_non_existent() )
2553             {
2554               ++nbValid;
2555               continue; // keep the sub-mesh
2556             }
2557           }
2558           CORBA::Object_var     smObj = _gen_i->SObjectToObject( smSO );
2559           SMESH::SMESH_subMesh_var sm = SMESH::SMESH_subMesh::_narrow( smObj );
2560           if ( !sm->_is_nil() && !sm->_non_existent() )
2561           {
2562             GEOM::GEOM_Object_var smGeom = sm->GetSubShape();
2563             if ( smGeom->_is_nil() )
2564             {
2565               RemoveSubMesh( sm );
2566               ++nbRemoved;
2567             }
2568           }
2569           else
2570           {
2571             if ( _preMeshInfo )
2572               _preMeshInfo->ForgetAllData(); // unknown hypothesis modified
2573             builder->RemoveObjectWithChildren( smSO ); // sub-shape removed before loading SMESH
2574             ++nbRemoved;
2575           }
2576         }
2577         if ( /*nbRemoved > 0 &&*/ nbValid == 0 )
2578           builder->RemoveObjectWithChildren( rootSO );
2579       }
2580   }
2581
2582   // check for removed sub-shapes and convert geom dependent groups into standalone ones
2583   std::map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_gr = _mapGroups.begin();
2584   while ( i_gr != _mapGroups.end())
2585   {
2586     SMESH::SMESH_GroupBase_ptr group = i_gr->second;
2587     ++i_gr;
2588     SALOMEDS::SObject_wrap        groupSO = _gen_i->ObjectToSObject( group ), refSO;
2589     SMESH::SMESH_GroupOnGeom_var   onGeom = SMESH::SMESH_GroupOnGeom::_narrow  ( group );
2590     SMESH::SMESH_GroupOnFilter_var onFilt = SMESH::SMESH_GroupOnFilter::_narrow( group );
2591     bool isValidGeom = false;
2592     if ( !onGeom->_is_nil() )
2593     {
2594       isValidGeom = ( ! GEOM::GEOM_Object_var( onGeom->GetShape() )->_is_nil() );
2595     }
2596     else if ( !onFilt->_is_nil() )
2597     {
2598       isValidGeom = isValidGeomFilter( onFilt->GetFilter() );
2599     }
2600     else // standalone
2601     {
2602       isValidGeom = ( !groupSO->_is_nil() &&
2603                       !groupSO->FindSubObject( SMESH::Tag_RefOnShape, refSO.inout() ));
2604     }
2605     if ( !isValidGeom )
2606     {
2607       if ( !IsLoaded() || group->IsEmpty() )
2608       {
2609         RemoveGroup( group );
2610       }
2611       else if ( !onGeom->_is_nil() || !onFilt->_is_nil() )
2612       {
2613         SMESH::SMESH_Group_var ( ConvertToStandalone( group ));
2614       }
2615       else // is it possible?
2616       {
2617         builder->RemoveObjectWithChildren( refSO );
2618       }
2619     }
2620   }
2621
2622
2623   if ( !_impl->HasShapeToMesh() ) return;
2624
2625   CORBA::Long nbEntities = NbNodes() + NbElements();
2626
2627   // Check if group contents changed
2628
2629   typedef map< string, TopoDS_Shape > TEntry2Geom;
2630   TEntry2Geom newGroupContents;
2631
2632   list<TGeomGroupData>::iterator
2633     data = _geomGroupData.begin(), dataEnd = _geomGroupData.end();
2634   for ( ; data != dataEnd; ++data )
2635   {
2636     pair< TEntry2Geom::iterator, bool > it_new =
2637       newGroupContents.insert( make_pair( data->_groupEntry, TopoDS_Shape() ));
2638     bool processedGroup    = !it_new.second;
2639     TopoDS_Shape& newShape = it_new.first->second;
2640     if ( !processedGroup )
2641       newShape = newGroupShape( *data, ONLY_IF_CHANGED );
2642     if ( newShape.IsNull() )
2643       continue; // no changes
2644
2645     if ( _preMeshInfo )
2646       _preMeshInfo->ForgetOrLoad();
2647
2648     if ( processedGroup ) { // update group indices
2649       list<TGeomGroupData>::iterator data2 = data;
2650       for ( --data2; data2->_groupEntry != data->_groupEntry; --data2) {}
2651       data->_indices = data2->_indices;
2652     }
2653
2654     // Update SMESH objects according to new GEOM group contents
2655
2656     SMESH::SMESH_subMesh_var submesh = SMESH::SMESH_subMesh::_narrow( data->_smeshObject );
2657     if ( !submesh->_is_nil() ) // -------------- Sub mesh ---------------------
2658     {
2659       int oldID = submesh->GetId();
2660       if ( !_mapSubMeshIor.count( oldID ))
2661         continue;
2662       TopoDS_Shape oldShape = _mapSubMesh[oldID]->GetSubShape();
2663
2664       // update hypotheses
2665       list <const SMESHDS_Hypothesis * > hyps = _impl->GetHypothesisList(oldShape);
2666       list <const SMESHDS_Hypothesis * >::iterator hypIt;
2667       for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2668       {
2669         _impl->RemoveHypothesis( oldShape, (*hypIt)->GetID());
2670         _impl->AddHypothesis   ( newShape, (*hypIt)->GetID());
2671       }
2672       // care of submeshes
2673       SMESH_subMesh* newSubmesh = _impl->GetSubMesh( newShape );
2674       int newID = newSubmesh->GetId();
2675       if ( newID != oldID ) {
2676         _mapSubMesh   [ newID ] = newSubmesh;
2677         _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
2678         _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
2679         _mapSubMesh.   erase(oldID);
2680         _mapSubMesh_i. erase(oldID);
2681         _mapSubMeshIor.erase(oldID);
2682         _mapSubMesh_i [ newID ]->changeLocalId( newID );
2683       }
2684       continue;
2685     }
2686
2687     SMESH::SMESH_GroupOnGeom_var smeshGroup =
2688       SMESH::SMESH_GroupOnGeom::_narrow( data->_smeshObject );
2689     if ( !smeshGroup->_is_nil() ) // ------------ GROUP -----------------------
2690     {
2691       SMESH_GroupOnGeom_i* group_i = SMESH::DownCast<SMESH_GroupOnGeom_i*>( smeshGroup );
2692       if ( group_i ) {
2693         ::SMESH_Group* group = _impl->GetGroup( group_i->GetLocalID() );
2694         SMESHDS_GroupOnGeom* ds = static_cast<SMESHDS_GroupOnGeom*>( group->GetGroupDS() );
2695         ds->SetShape( newShape );
2696       }
2697       continue;
2698     }
2699
2700     SMESH::SMESH_Mesh_var mesh = SMESH::SMESH_Mesh::_narrow( data->_smeshObject );
2701     if ( !mesh->_is_nil() ) // -------------- MESH ----------------------------
2702     {
2703       // Remove groups and submeshes basing on removed sub-shapes
2704
2705       TopTools_MapOfShape newShapeMap;
2706       TopoDS_Iterator shapeIt( newShape );
2707       for ( ; shapeIt.More(); shapeIt.Next() )
2708         newShapeMap.Add( shapeIt.Value() );
2709
2710       SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
2711       for ( shapeIt.Initialize( meshDS->ShapeToMesh() ); shapeIt.More(); shapeIt.Next() )
2712       {
2713         if ( newShapeMap.Contains( shapeIt.Value() ))
2714           continue;
2715         TopTools_IndexedMapOfShape oldShapeMap;
2716         TopExp::MapShapes( shapeIt.Value(), oldShapeMap );
2717         for ( int i = 1; i <= oldShapeMap.Extent(); ++i )
2718         {
2719           const TopoDS_Shape& oldShape = oldShapeMap(i);
2720           int oldInd = meshDS->ShapeToIndex( oldShape );
2721           // -- submeshes --
2722           map<int, SMESH::SMESH_subMesh_ptr>::iterator i_smIor = _mapSubMeshIor.find( oldInd );
2723           if ( i_smIor != _mapSubMeshIor.end() ) {
2724             RemoveSubMesh( i_smIor->second ); // one submesh per shape index
2725           }
2726           // --- groups ---
2727           map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_grp = _mapGroups.begin();
2728           for ( ; i_grp != _mapGroups.end(); ++i_grp )
2729           {
2730             // check if a group bases on oldInd shape
2731             SMESHDS_GroupOnGeom* grpOnGeom = 0;
2732             if ( ::SMESH_Group* g = _impl->GetGroup( i_grp->first ))
2733               grpOnGeom = dynamic_cast<SMESHDS_GroupOnGeom*>( g->GetGroupDS() );
2734             if ( grpOnGeom && oldShape.IsSame( grpOnGeom->GetShape() ))
2735             { // remove
2736               RemoveGroup( i_grp->second ); // several groups can base on same shape
2737               i_grp = _mapGroups.begin(); // _mapGroups changed - restart iteration
2738             }
2739           }
2740         }
2741       }
2742       // Reassign hypotheses and update groups after setting the new shape to mesh
2743
2744       // collect anassigned hypotheses
2745       typedef list< pair< TIndexedShape, list<const SMESHDS_Hypothesis*> > > TShapeHypList;
2746       list <const SMESHDS_Hypothesis * >::const_iterator hypIt;
2747       TShapeHypList assignedHyps;
2748       for ( int i = 1; i <= meshDS->MaxShapeIndex(); ++i )
2749       {
2750         const TopoDS_Shape& oldShape = meshDS->IndexToShape(i);
2751         list<const SMESHDS_Hypothesis*> hyps = meshDS->GetHypothesis( oldShape );// copy
2752         if ( !hyps.empty() ) {
2753           assignedHyps.push_back( make_pair( TIndexedShape(i,oldShape), hyps ));
2754           for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2755             _impl->RemoveHypothesis( oldShape, (*hypIt)->GetID());
2756         }
2757       }
2758       // collect shapes supporting groups
2759       typedef list < pair< TIndexedShape, SMDSAbs_ElementType > > TShapeTypeList;
2760       TShapeTypeList groupData;
2761       const set<SMESHDS_GroupBase*>& groups = meshDS->GetGroups();
2762       set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2763       for ( ; grIt != groups.end(); ++grIt )
2764       {
2765         if ( SMESHDS_GroupOnGeom* gog = dynamic_cast<SMESHDS_GroupOnGeom*>( *grIt ))
2766           groupData.push_back
2767             ( make_pair( TIndexedShape( gog->GetID(),gog->GetShape()), gog->GetType()));
2768       }
2769       // set new shape to mesh -> DS of sub-meshes and geom groups is deleted
2770       _impl->Clear();
2771       _impl->ShapeToMesh( TopoDS_Shape() ); // IPAL52730
2772       _impl->ShapeToMesh( newShape );
2773
2774       // reassign hypotheses
2775       TShapeHypList::iterator indS_hyps = assignedHyps.begin();
2776       for ( ; indS_hyps != assignedHyps.end(); ++indS_hyps )
2777       {
2778         TIndexedShape&                   geom = indS_hyps->first;
2779         list<const SMESHDS_Hypothesis*>& hyps = indS_hyps->second;
2780         int oldID = geom._index;
2781         int newID = meshDS->ShapeToIndex( geom._shape );
2782         if ( oldID == 1 ) { // main shape
2783           newID = 1;
2784           geom._shape = newShape;
2785         }
2786         if ( !newID )
2787           continue;
2788         for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2789           _impl->AddHypothesis( geom._shape, (*hypIt)->GetID());
2790         // care of sub-meshes
2791         SMESH_subMesh* newSubmesh = _impl->GetSubMesh( geom._shape );
2792         if ( newID != oldID ) {
2793           _mapSubMesh   [ newID ] = newSubmesh;
2794           _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
2795           _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
2796           _mapSubMesh.   erase(oldID);
2797           _mapSubMesh_i. erase(oldID);
2798           _mapSubMeshIor.erase(oldID);
2799           _mapSubMesh_i [ newID ]->changeLocalId( newID );
2800         }
2801       }
2802       // recreate groups
2803       TShapeTypeList::iterator geomType = groupData.begin();
2804       for ( ; geomType != groupData.end(); ++geomType )
2805       {
2806         const TIndexedShape& geom = geomType->first;
2807         int oldID = geom._index;
2808         if ( _mapGroups.find( oldID ) == _mapGroups.end() )
2809           continue;
2810         // get group name
2811         SALOMEDS::SObject_wrap groupSO = _gen_i->ObjectToSObject( _mapGroups[oldID] );
2812         CORBA::String_var      name    = groupSO->GetName();
2813         // update
2814         if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>(_mapGroups[oldID]))
2815           if ( SMESH_Group* group = _impl->AddGroup( geomType->second, name.in(),
2816                                                      /*id=*/-1, geom._shape ))
2817             group_i->changeLocalId( group->GetID() );
2818       }
2819
2820       break; // everything has been updated
2821
2822     } // update mesh
2823   } // loop on group data
2824
2825   // Update icons
2826
2827   CORBA::Long newNbEntities = NbNodes() + NbElements();
2828   list< SALOMEDS::SObject_wrap > soToUpdateIcons;
2829   if ( newNbEntities != nbEntities )
2830   {
2831     // Add all SObjects with icons to soToUpdateIcons
2832     soToUpdateIcons.push_back( _gen_i->ObjectToSObject( _this() )); // mesh
2833
2834     for (map<int, SMESH::SMESH_subMesh_ptr>::iterator i_sm = _mapSubMeshIor.begin();
2835          i_sm != _mapSubMeshIor.end(); ++i_sm ) // submeshes
2836       soToUpdateIcons.push_back( _gen_i->ObjectToSObject( i_sm->second ));
2837
2838     for ( map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_gr = _mapGroups.begin();
2839           i_gr != _mapGroups.end(); ++i_gr ) // groups
2840       soToUpdateIcons.push_back( _gen_i->ObjectToSObject( i_gr->second ));
2841   }
2842
2843   list< SALOMEDS::SObject_wrap >::iterator so = soToUpdateIcons.begin();
2844   for ( ; so != soToUpdateIcons.end(); ++so )
2845     _gen_i->SetPixMap( *so, "ICON_SMESH_TREE_MESH_WARN" );
2846 }
2847
2848 //=============================================================================
2849 /*!
2850  * \brief Create standalone group from a group on geometry or filter
2851  */
2852 //=============================================================================
2853
2854 SMESH::SMESH_Group_ptr SMESH_Mesh_i::ConvertToStandalone( SMESH::SMESH_GroupBase_ptr theGroup )
2855   throw (SALOME::SALOME_Exception)
2856 {
2857   SMESH::SMESH_Group_var aGroup;
2858
2859   SMESH_TRY;
2860
2861   if ( _preMeshInfo )
2862     _preMeshInfo->FullLoadFromFile();
2863
2864   if ( theGroup->_is_nil() )
2865     return aGroup._retn();
2866
2867   SMESH_GroupBase_i* aGroupToRem = SMESH::DownCast<SMESH_GroupBase_i*>( theGroup );
2868   if ( !aGroupToRem )
2869     return aGroup._retn();
2870
2871   const bool isOnFilter = ( SMESH::DownCast< SMESH_GroupOnFilter_i* > ( theGroup ));
2872
2873   const int anId = aGroupToRem->GetLocalID();
2874   if ( !_impl->ConvertToStandalone( anId ) )
2875     return aGroup._retn();
2876   removeGeomGroupData( theGroup );
2877
2878   SMESH_GroupBase_i* aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
2879
2880   // remove old instance of group from own map
2881   { SMESH::SMESH_GroupBase_var var( _mapGroups[anId] ); } // decref CORBA object
2882   _mapGroups.erase( anId );
2883
2884   SALOMEDS::StudyBuilder_var builder;
2885   SALOMEDS::SObject_wrap     aGroupSO;
2886   SALOMEDS::Study_var        aStudy = SMESH_Gen_i::getStudyServant();
2887   if ( !aStudy->_is_nil() ) {
2888     builder  = aStudy->NewBuilder();
2889     aGroupSO = _gen_i->ObjectToSObject( theGroup );
2890     if ( !aGroupSO->_is_nil() )
2891     {
2892       // remove reference to geometry
2893       SALOMEDS::ChildIterator_wrap chItr = aStudy->NewChildIterator(aGroupSO);
2894       for ( ; chItr->More(); chItr->Next() )
2895       {
2896         // Remove group's child SObject
2897         SALOMEDS::SObject_wrap so = chItr->Value();
2898         builder->RemoveObject( so );
2899       }
2900       // Update Python script
2901       TPythonDump() << aGroupSO << " = " << SMESH::SMESH_Mesh_var(_this())
2902                     << ".ConvertToStandalone( " << aGroupSO << " )";
2903
2904       // change icon of Group on Filter
2905       if ( isOnFilter )
2906       {
2907         // SMESH::array_of_ElementType_var elemTypes = aGroupImpl->GetTypes();
2908         // const int isEmpty = ( elemTypes->length() == 0 );
2909         // if ( !isEmpty )
2910         {
2911           SALOMEDS::GenericAttribute_wrap anAttr =
2912             builder->FindOrCreateAttribute( aGroupSO, "AttributePixMap" );
2913           SALOMEDS::AttributePixMap_wrap pm = anAttr;
2914           pm->SetPixMap( "ICON_SMESH_TREE_GROUP" );
2915         }
2916       }
2917     }
2918   }
2919
2920   // remember new group in own map
2921   aGroup = SMESH::SMESH_Group::_narrow( aGroupImpl->_this() );
2922   _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( aGroup );
2923
2924   // register CORBA object for persistence
2925   _gen_i->RegisterObject( aGroup );
2926
2927   CORBA::String_var ior = _gen_i->GetORB()->object_to_string( aGroup );
2928   builder->SetIOR( aGroupSO, ior.in() ); //  == aGroup->Register();
2929   //aGroup->Register();
2930   aGroupToRem->UnRegister();
2931
2932   SMESH_CATCH( SMESH::throwCorbaException );
2933
2934   return aGroup._retn();
2935 }
2936
2937 //=============================================================================
2938 /*!
2939  *
2940  */
2941 //=============================================================================
2942
2943 SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::createSubMesh( GEOM::GEOM_Object_ptr theSubShapeObject )
2944 {
2945   if(MYDEBUG) MESSAGE( "createSubMesh" );
2946   TopoDS_Shape  myLocSubShape = _gen_i->GeomObjectToShape(theSubShapeObject);
2947   ::SMESH_subMesh * mySubMesh = _impl->GetSubMesh(myLocSubShape);
2948   int               subMeshId = 0;
2949
2950   SMESH_subMesh_i * subMeshServant;
2951   if ( mySubMesh )
2952   {
2953     subMeshId = mySubMesh->GetId();
2954     subMeshServant = new SMESH_subMesh_i(myPOA, _gen_i, this, subMeshId);
2955   }
2956   else // "invalid sub-mesh"
2957   {
2958     // The invalid sub-mesh is created for the case where a valid sub-shape not found
2959     // by SMESH_Gen_i::CopyMeshWithGeom(). The invalid sub-mesh has GetId() < 0.
2960     if ( _mapSubMesh.empty() )
2961       subMeshId = -1;
2962     else
2963       subMeshId = _mapSubMesh.begin()->first - 1;
2964     subMeshServant = new SMESH_Invalid_subMesh_i(myPOA, _gen_i, this, subMeshId, theSubShapeObject);
2965   }
2966
2967   SMESH::SMESH_subMesh_var subMesh = subMeshServant->_this();
2968
2969   _mapSubMesh   [subMeshId] = mySubMesh;
2970   _mapSubMesh_i [subMeshId] = subMeshServant;
2971   _mapSubMeshIor[subMeshId] = SMESH::SMESH_subMesh::_duplicate( subMesh );
2972
2973   subMeshServant->Register();
2974
2975   // register CORBA object for persistence
2976   int nextId = _gen_i->RegisterObject( subMesh );
2977   if(MYDEBUG) { MESSAGE( "Add submesh to map with id = "<< nextId); }
2978   else        { nextId = 0; } // avoid "unused variable" warning
2979
2980   // to track changes of GEOM groups
2981   if ( subMeshId > 0 )
2982     addGeomGroupData( theSubShapeObject, subMesh );
2983
2984   return subMesh._retn();
2985 }
2986
2987 //=======================================================================
2988 //function : getSubMesh
2989 //purpose  :
2990 //=======================================================================
2991
2992 SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::getSubMesh(int shapeID)
2993 {
2994   map<int, SMESH::SMESH_subMesh_ptr>::iterator it = _mapSubMeshIor.find( shapeID );
2995   if ( it == _mapSubMeshIor.end() )
2996     return SMESH::SMESH_subMesh::_nil();
2997
2998   return SMESH::SMESH_subMesh::_duplicate( (*it).second );
2999 }
3000
3001 //=============================================================================
3002 /*!
3003  *
3004  */
3005 //=============================================================================
3006
3007 bool SMESH_Mesh_i::removeSubMesh (SMESH::SMESH_subMesh_ptr theSubMesh,
3008                                   GEOM::GEOM_Object_ptr    theSubShapeObject )
3009 {
3010   bool isHypChanged = false;
3011   if ( theSubMesh->_is_nil() /*|| theSubShapeObject->_is_nil()*/ )
3012     return isHypChanged;
3013
3014   const int subMeshId = theSubMesh->GetId();
3015
3016   if ( theSubShapeObject->_is_nil() )  // not published shape (IPAL13617)
3017   {
3018     SMESH_subMesh* sm;
3019     if (( _mapSubMesh.count( subMeshId )) &&
3020         ( sm = _impl->GetSubMeshContaining( subMeshId )))
3021     {
3022       TopoDS_Shape S = sm->GetSubShape();
3023       if ( !S.IsNull() )
3024       {
3025         list<const SMESHDS_Hypothesis*> hyps = _impl->GetHypothesisList( S );
3026         isHypChanged = !hyps.empty();
3027         if ( isHypChanged && _preMeshInfo )
3028           _preMeshInfo->ForgetOrLoad();
3029         list<const SMESHDS_Hypothesis*>::const_iterator hyp = hyps.begin();
3030         for ( ; hyp != hyps.end(); ++hyp )
3031           _impl->RemoveHypothesis(S, (*hyp)->GetID());
3032       }
3033     }
3034   }
3035   else
3036   {
3037     try {
3038       SMESH::ListOfHypothesis_var aHypList = GetHypothesisList( theSubShapeObject );
3039       isHypChanged = ( aHypList->length() > 0 );
3040       for ( int i = 0, n = aHypList->length(); i < n; i++ ) {
3041         removeHypothesis( theSubShapeObject, aHypList[i] );
3042       }
3043     }
3044     catch( const SALOME::SALOME_Exception& ) {
3045       INFOS("SMESH_Mesh_i::removeSubMesh(): exception caught!");
3046     }
3047     removeGeomGroupData( theSubShapeObject );
3048   }
3049
3050   // remove a servant
3051   std::map<int, SMESH_subMesh_i*>::iterator id_smi = _mapSubMesh_i.find( subMeshId );
3052   if ( id_smi != _mapSubMesh_i.end() )
3053     id_smi->second->UnRegister();
3054
3055   // remove a CORBA object
3056   std::map<int, SMESH::SMESH_subMesh_ptr>::iterator id_smptr = _mapSubMeshIor.find( subMeshId );
3057   if ( id_smptr != _mapSubMeshIor.end() )
3058     SMESH::SMESH_subMesh_var( id_smptr->second );
3059
3060   _mapSubMesh.erase(subMeshId);
3061   _mapSubMesh_i.erase(subMeshId);
3062   _mapSubMeshIor.erase(subMeshId);
3063
3064   return isHypChanged;
3065 }
3066
3067 //=============================================================================
3068 /*!
3069  *
3070  */
3071 //=============================================================================
3072
3073 SMESH::SMESH_GroupBase_ptr SMESH_Mesh_i::createGroup (SMESH::ElementType        theElemType,
3074                                                       const char*               theName,
3075                                                       const int                 theID,
3076                                                       const TopoDS_Shape&       theShape,
3077                                                       const SMESH_PredicatePtr& thePredicate )
3078 {
3079   std::string newName;
3080   if ( !theName || !theName[0] )
3081   {
3082     std::set< std::string > presentNames;
3083     std::map<int, SMESH::SMESH_GroupBase_ptr>::const_iterator i_gr = _mapGroups.begin();
3084     for ( ; i_gr != _mapGroups.end(); ++i_gr )
3085     {
3086       CORBA::String_var name = i_gr->second->GetName();
3087       presentNames.insert( name.in() );
3088     }
3089     do {
3090       newName = "noname_Group_" + SMESH_Comment( presentNames.size() + 1 );
3091     } while ( !presentNames.insert( newName ).second );
3092     theName = newName.c_str();
3093   }
3094   SMESH::SMESH_GroupBase_var aGroup;
3095   if ( SMESH_Group* g = _impl->AddGroup( (SMDSAbs_ElementType)theElemType, theName,
3096                                          theID, theShape, thePredicate ))
3097   {
3098     int anId = g->GetID();
3099     SMESH_GroupBase_i* aGroupImpl;
3100     if ( !theShape.IsNull() )
3101       aGroupImpl = new SMESH_GroupOnGeom_i( SMESH_Gen_i::GetPOA(), this, anId );
3102     else if ( thePredicate )
3103       aGroupImpl = new SMESH_GroupOnFilter_i( SMESH_Gen_i::GetPOA(), this, anId );
3104     else
3105       aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
3106
3107     aGroup = aGroupImpl->_this();
3108     _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( aGroup );
3109     aGroupImpl->Register();
3110
3111     // register CORBA object for persistence
3112     int nextId = _gen_i->RegisterObject( aGroup );
3113     if(MYDEBUG) { MESSAGE( "Add group to map with id = "<< nextId); }
3114     else        { nextId = ( nextId > 0 ); } // avoid "unused variable" warning in release mode
3115
3116     // to track changes of GEOM groups
3117     if ( !theShape.IsNull() ) {
3118       GEOM::GEOM_Object_var geom = _gen_i->ShapeToGeomObject( theShape );
3119       addGeomGroupData( geom, aGroup );
3120     }
3121   }
3122   return aGroup._retn();
3123 }
3124
3125 //=============================================================================
3126 /*!
3127  * SMESH_Mesh_i::removeGroup
3128  *
3129  * Should be called by ~SMESH_Group_i()
3130  */
3131 //=============================================================================
3132
3133 void SMESH_Mesh_i::removeGroup( const int theId )
3134 {
3135   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::removeGroup()" );
3136   if ( _mapGroups.find( theId ) != _mapGroups.end() ) {
3137     SMESH::SMESH_GroupBase_var group = _mapGroups[theId];
3138     _mapGroups.erase( theId );
3139     removeGeomGroupData( group );
3140     if ( !_impl->RemoveGroup( theId ))
3141     {
3142       // it seems to be a call up from _impl caused by hyp modification (issue 0020918)
3143       RemoveGroup( group );
3144     }
3145     group->UnRegister();
3146   }
3147 }
3148
3149 //=============================================================================
3150 /*!
3151  *
3152  */
3153 //=============================================================================
3154
3155 SMESH::log_array * SMESH_Mesh_i::GetLog(CORBA::Boolean clearAfterGet)
3156   throw(SALOME::SALOME_Exception)
3157 {
3158   SMESH::log_array_var aLog;
3159
3160   SMESH_TRY;
3161   if ( _preMeshInfo )
3162     _preMeshInfo->FullLoadFromFile();
3163
3164   list < SMESHDS_Command * >logDS = _impl->GetLog();
3165   aLog = new SMESH::log_array;
3166   int indexLog = 0;
3167   int lg = logDS.size();
3168   SCRUTE(lg);
3169   aLog->length(lg);
3170   list < SMESHDS_Command * >::iterator its = logDS.begin();
3171   while(its != logDS.end()){
3172     SMESHDS_Command *com = *its;
3173     int comType = com->GetType();
3174     //SCRUTE(comType);
3175     int lgcom = com->GetNumber();
3176     //SCRUTE(lgcom);
3177     const list < int >&intList = com->GetIndexes();
3178     int inum = intList.size();
3179     //SCRUTE(inum);
3180     list < int >::const_iterator ii = intList.begin();
3181     const list < double >&coordList = com->GetCoords();
3182     int rnum = coordList.size();
3183     //SCRUTE(rnum);
3184     list < double >::const_iterator ir = coordList.begin();
3185     aLog[indexLog].commandType = comType;
3186     aLog[indexLog].number = lgcom;
3187     aLog[indexLog].coords.length(rnum);
3188     aLog[indexLog].indexes.length(inum);
3189     for(int i = 0; i < rnum; i++){
3190       aLog[indexLog].coords[i] = *ir;
3191       //MESSAGE(" "<<i<<" "<<ir.Value());
3192       ir++;
3193     }
3194     for(int i = 0; i < inum; i++){
3195       aLog[indexLog].indexes[i] = *ii;
3196       //MESSAGE(" "<<i<<" "<<ii.Value());
3197       ii++;
3198     }
3199     indexLog++;
3200     its++;
3201   }
3202   if(clearAfterGet)
3203     _impl->ClearLog();
3204
3205   SMESH_CATCH( SMESH::throwCorbaException );
3206
3207   return aLog._retn();
3208 }
3209
3210
3211 //=============================================================================
3212 /*!
3213  *
3214  */
3215 //=============================================================================
3216
3217 void SMESH_Mesh_i::ClearLog() throw(SALOME::SALOME_Exception)
3218 {
3219   SMESH_TRY;
3220   _impl->ClearLog();
3221   SMESH_CATCH( SMESH::throwCorbaException );
3222 }
3223
3224 //=============================================================================
3225 /*!
3226  *
3227  */
3228 //=============================================================================
3229
3230 CORBA::Long SMESH_Mesh_i::GetId()throw(SALOME::SALOME_Exception)
3231 {
3232   return _id;
3233 }
3234
3235 //=============================================================================
3236 namespace
3237 {
3238   //!< implementation of struct used to call methods of SMESH_Mesh_i from SMESH_Mesh
3239   // issue 0020918: groups removal is caused by hyp modification
3240   // issue 0021208: to forget not loaded mesh data at hyp modification
3241   struct TCallUp_i : public SMESH_Mesh::TCallUp
3242   {
3243     SMESH_Mesh_i* _mesh;
3244     TCallUp_i(SMESH_Mesh_i* mesh):_mesh(mesh) {}
3245     virtual void RemoveGroup (const int theGroupID) { _mesh->removeGroup( theGroupID ); }
3246     virtual void HypothesisModified( int hypID,
3247                                      bool updIcons) { _mesh->onHypothesisModified( hypID,
3248                                                                                    updIcons ); }
3249     virtual void Load ()                            { _mesh->Load(); }
3250     virtual bool IsLoaded()                         { return _mesh->IsLoaded(); }
3251   };
3252 }
3253
3254 //================================================================================
3255 /*!
3256  * \brief callback from _impl to
3257  *     1) forget not loaded mesh data (issue 0021208)
3258  *     2) mark hypothesis as valid
3259  */
3260 //================================================================================
3261
3262 void SMESH_Mesh_i::onHypothesisModified(int theHypID, bool theUpdateIcons)
3263 {
3264   if ( _preMeshInfo )
3265     _preMeshInfo->ForgetOrLoad();
3266
3267   if ( theUpdateIcons )
3268   {
3269     SMESH::SMESH_Mesh_var mesh = _this();
3270     _gen_i->UpdateIcons( mesh );
3271   }
3272
3273   if ( _nbInvalidHypos != 0 )
3274   {
3275     // mark a hypothesis as valid after edition
3276     int nbInvalid = 0;
3277     SALOMEDS::SComponent_wrap smeshComp = _gen_i->PublishComponent();
3278     SALOMEDS::SObject_wrap hypRoot;
3279     if ( !smeshComp->_is_nil() &&
3280          smeshComp->FindSubObject( _gen_i->GetHypothesisRootTag(), hypRoot.inout() ))
3281     {
3282       SALOMEDS::ChildIterator_wrap anIter = _gen_i->getStudyServant()->NewChildIterator( hypRoot );
3283       for ( ; anIter->More(); anIter->Next() )
3284       {
3285         SALOMEDS::SObject_wrap    hypSO = anIter->Value();
3286         CORBA::Object_var           obj = _gen_i->SObjectToObject( hypSO );
3287         SMESH::SMESH_Hypothesis_var hyp = SMESH::SMESH_Hypothesis::_narrow( obj );
3288         if ( !hyp->_is_nil() && hyp->GetId() == theHypID )
3289           _gen_i->HighLightInvalid( hyp, false );
3290         else
3291           nbInvalid += _gen_i->IsInvalid( hypSO );
3292       }
3293     }
3294     _nbInvalidHypos = nbInvalid;
3295   }
3296 }
3297
3298 //=============================================================================
3299 /*!
3300  *
3301  */
3302 //=============================================================================
3303
3304 void SMESH_Mesh_i::SetImpl(::SMESH_Mesh * impl)
3305 {
3306   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::SetImpl");
3307   _impl = impl;
3308   if ( _impl )
3309     _impl->SetCallUp( new TCallUp_i(this));
3310 }
3311
3312 //=============================================================================
3313 /*!
3314  *
3315  */
3316 //=============================================================================
3317
3318 ::SMESH_Mesh & SMESH_Mesh_i::GetImpl()
3319 {
3320   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::GetImpl()");
3321   return *_impl;
3322 }
3323
3324 //=============================================================================
3325 /*!
3326  * Return mesh editor
3327  */
3328 //=============================================================================
3329
3330 SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditor()
3331   throw (SALOME::SALOME_Exception)
3332 {
3333   SMESH::SMESH_MeshEditor_var aMeshEdVar;
3334
3335   SMESH_TRY;
3336   if ( _preMeshInfo )
3337     _preMeshInfo->FullLoadFromFile();
3338
3339   // Create MeshEditor
3340   if ( !_editor )
3341     _editor = new SMESH_MeshEditor_i( this, false );
3342   aMeshEdVar = _editor->_this();
3343
3344   // Update Python script
3345   TPythonDump() << _editor << " = "
3346                 << SMESH::SMESH_Mesh_var(_this()) << ".GetMeshEditor()";
3347
3348   SMESH_CATCH( SMESH::throwCorbaException );
3349
3350   return aMeshEdVar._retn();
3351 }
3352
3353 //=============================================================================
3354 /*!
3355  * Return mesh edition previewer
3356  */
3357 //=============================================================================
3358
3359 SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditPreviewer()
3360   throw (SALOME::SALOME_Exception)
3361 {
3362   SMESH::SMESH_MeshEditor_var aMeshEdVar;
3363
3364   SMESH_TRY;
3365   if ( _preMeshInfo )
3366     _preMeshInfo->FullLoadFromFile();
3367
3368   if ( !_previewEditor )
3369     _previewEditor = new SMESH_MeshEditor_i( this, true );
3370   aMeshEdVar = _previewEditor->_this();
3371
3372   SMESH_CATCH( SMESH::throwCorbaException );
3373
3374   return aMeshEdVar._retn();
3375 }
3376
3377 //================================================================================
3378 /*!
3379  * \brief Return true if the mesh has been edited since a last total re-compute
3380  *        and those modifications may prevent successful partial re-compute
3381  */
3382 //================================================================================
3383
3384 CORBA::Boolean SMESH_Mesh_i::HasModificationsToDiscard() throw(SALOME::SALOME_Exception)
3385 {
3386   Unexpect aCatch(SALOME_SalomeException);
3387   return _impl->HasModificationsToDiscard();
3388 }
3389
3390 //================================================================================
3391 /*!
3392  * \brief Returns a random unique color
3393  */
3394 //================================================================================
3395
3396 static SALOMEDS::Color getUniqueColor( const std::list<SALOMEDS::Color>& theReservedColors )
3397 {
3398   const int MAX_ATTEMPTS = 100;
3399   int cnt = 0;
3400   double tolerance = 0.5;
3401   SALOMEDS::Color col;
3402
3403   bool ok = false;
3404   while ( !ok ) {
3405     // generate random color
3406     double red    = (double)rand() / RAND_MAX;
3407     double green  = (double)rand() / RAND_MAX;
3408     double blue   = (double)rand() / RAND_MAX;
3409     // check existence in the list of the existing colors
3410     bool matched = false;
3411     std::list<SALOMEDS::Color>::const_iterator it;
3412     for ( it = theReservedColors.begin(); it != theReservedColors.end() && !matched; ++it ) {
3413       SALOMEDS::Color color = *it;
3414       double tol = fabs( color.R - red ) + fabs( color.G - green ) + fabs( color.B  - blue  );
3415       matched = tol < tolerance;
3416     }
3417     if ( (cnt+1) % 20 == 0 ) tolerance = tolerance/2;
3418     ok = ( ++cnt == MAX_ATTEMPTS ) || !matched;
3419     col.R = red;
3420     col.G = green;
3421     col.B = blue;
3422   }
3423   return col;
3424 }
3425
3426 //=============================================================================
3427 /*!
3428  * Sets auto-color mode. If it is on, groups get unique random colors
3429  */
3430 //=============================================================================
3431
3432 void SMESH_Mesh_i::SetAutoColor(CORBA::Boolean theAutoColor) throw(SALOME::SALOME_Exception)
3433 {
3434   Unexpect aCatch(SALOME_SalomeException);
3435   _impl->SetAutoColor(theAutoColor);
3436
3437   TPythonDump pyDump; // not to dump group->SetColor() from below code
3438   pyDump << SMESH::SMESH_Mesh_var(_this()) <<".SetAutoColor( "<<theAutoColor<<" )";
3439
3440   std::list<SALOMEDS::Color> aReservedColors;
3441   map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.begin();
3442   for ( ; it != _mapGroups.end(); it++ ) {
3443     if ( CORBA::is_nil( it->second )) continue;
3444     SALOMEDS::Color aColor = getUniqueColor( aReservedColors );
3445     it->second->SetColor( aColor );
3446     aReservedColors.push_back( aColor );
3447   }
3448 }
3449
3450 //=============================================================================
3451 /*!
3452  * Returns true if auto-color mode is on
3453  */
3454 //=============================================================================
3455
3456 CORBA::Boolean SMESH_Mesh_i::GetAutoColor() throw(SALOME::SALOME_Exception)
3457 {
3458   Unexpect aCatch(SALOME_SalomeException);
3459   return _impl->GetAutoColor();
3460 }
3461
3462 //=============================================================================
3463 /*!
3464  *  Checks if there are groups with equal names
3465  */
3466 //=============================================================================
3467
3468 CORBA::Boolean SMESH_Mesh_i::HasDuplicatedGroupNamesMED()
3469 {
3470   return _impl->HasDuplicatedGroupNamesMED();
3471 }
3472
3473 //================================================================================
3474 /*!
3475  * \brief Care of a file before exporting mesh into it
3476  */
3477 //================================================================================
3478
3479 void SMESH_Mesh_i::PrepareForWriting (const char* file, bool overwrite)
3480 {
3481   SMESH_File aFile( file, false );
3482   SMESH_Comment msg;
3483   if ( aFile.exists() ) {
3484     // existing filesystem node
3485     if ( !aFile.isDirectory() ) {
3486       if ( aFile.openForWriting() ) {
3487         if ( overwrite && ! aFile.remove()) {
3488           msg << "Can't replace " << aFile.getName();
3489         }
3490       } else {
3491         msg << "Can't write into " << aFile.getName();
3492       }
3493     } else {
3494       msg << "Location " << aFile.getName() << " is not a file";
3495     }
3496   }
3497   else {
3498     // nonexisting file; check if it can be created
3499     if ( !aFile.openForWriting() ) {
3500       msg << "You cannot create the file "
3501           << aFile.getName()
3502           << ". Check the directory existence and access rights";
3503     }
3504     aFile.remove();
3505   }
3506
3507   if ( !msg.empty() )
3508   {
3509     msg << ".";
3510     THROW_SALOME_CORBA_EXCEPTION(msg.c_str(), SALOME::BAD_PARAM);
3511   }
3512 }
3513
3514 //================================================================================
3515 /*!
3516  * \brief Prepares a file for export and pass names of mesh groups from study to mesh DS
3517  *  \param file - file name
3518  *  \param overwrite - to erase the file or not
3519  *  \retval string - mesh name
3520  */
3521 //================================================================================
3522
3523 string SMESH_Mesh_i::prepareMeshNameAndGroups(const char*    file,
3524                                               CORBA::Boolean overwrite)
3525 {
3526   // Perform Export
3527   PrepareForWriting(file, overwrite);
3528   string aMeshName = "Mesh";
3529   SALOMEDS::Study_var aStudy = SMESH_Gen_i::getStudyServant();
3530   if ( !aStudy->_is_nil() ) {
3531     SALOMEDS::SObject_wrap aMeshSO = _gen_i->ObjectToSObject(  _this() );
3532     if ( !aMeshSO->_is_nil() ) {
3533       CORBA::String_var name = aMeshSO->GetName();
3534       aMeshName = name;
3535       // asv : 27.10.04 : fix of 6903: check for StudyLocked before adding attributes
3536       if ( !aStudy->GetProperties()->IsLocked() )
3537       {
3538         SALOMEDS::GenericAttribute_wrap anAttr;
3539         SALOMEDS::StudyBuilder_var aStudyBuilder = aStudy->NewBuilder();
3540         anAttr=aStudyBuilder->FindOrCreateAttribute(aMeshSO, "AttributeExternalFileDef");
3541         SALOMEDS::AttributeExternalFileDef_wrap aFileName = anAttr;
3542         ASSERT(!aFileName->_is_nil());
3543         aFileName->SetValue(file);
3544         anAttr=aStudyBuilder->FindOrCreateAttribute(aMeshSO, "AttributeFileType");
3545         SALOMEDS::AttributeFileType_wrap aFileType = anAttr;
3546         ASSERT(!aFileType->_is_nil());
3547         aFileType->SetValue("FICHIERMED");
3548       }
3549     }
3550   }
3551   // Update Python script
3552   // set name of mesh before export
3553   TPythonDump() << _gen_i << ".SetName("
3554                 << SMESH::SMESH_Mesh_var(_this()) << ", '" << aMeshName.c_str() << "')";
3555
3556   // check names of groups
3557   checkGroupNames();
3558
3559   return aMeshName;
3560 }
3561
3562 //================================================================================
3563 /*!
3564  * \brief Export to MED file
3565  */
3566 //================================================================================
3567
3568 void SMESH_Mesh_i::ExportMED(const char*        file,
3569                              CORBA::Boolean     auto_groups,
3570                              CORBA::Long        version,
3571                              CORBA::Boolean     overwrite,
3572                              CORBA::Boolean     autoDimension)
3573   throw(SALOME::SALOME_Exception)
3574 {
3575   //MESSAGE("MED minor version: "<< minor);
3576   SMESH_TRY;
3577   if ( _preMeshInfo )
3578     _preMeshInfo->FullLoadFromFile();
3579
3580   string aMeshName = prepareMeshNameAndGroups(file, overwrite);
3581   _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version, 0, autoDimension );
3582
3583   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportMED( r'"
3584                 << file << "', "
3585                 << "auto_groups=" <<auto_groups << ", "
3586                 << "minor=" << version <<  ", "
3587                 << "overwrite=" << overwrite << ", "
3588                 << "meshPart=None, "
3589                 << "autoDimension=" << autoDimension << " )";
3590
3591   SMESH_CATCH( SMESH::throwCorbaException );
3592 }
3593
3594 //================================================================================
3595 /*!
3596  * \brief Export a mesh to a SAUV file
3597  */
3598 //================================================================================
3599
3600 void SMESH_Mesh_i::ExportSAUV (const char* file,
3601                                CORBA::Boolean auto_groups)
3602   throw(SALOME::SALOME_Exception)
3603 {
3604   Unexpect aCatch(SALOME_SalomeException);
3605   if ( _preMeshInfo )
3606     _preMeshInfo->FullLoadFromFile();
3607
3608   string aMeshName = prepareMeshNameAndGroups(file, true);
3609   TPythonDump() << SMESH::SMESH_Mesh_var( _this())
3610                 << ".ExportSAUV( r'" << file << "', " << auto_groups << " )";
3611   _impl->ExportSAUV(file, aMeshName.c_str(), auto_groups);
3612 }
3613
3614
3615 //================================================================================
3616 /*!
3617  * \brief Export a mesh to a DAT file
3618  */
3619 //================================================================================
3620
3621 void SMESH_Mesh_i::ExportDAT (const char *file)
3622   throw(SALOME::SALOME_Exception)
3623 {
3624   Unexpect aCatch(SALOME_SalomeException);
3625   if ( _preMeshInfo )
3626     _preMeshInfo->FullLoadFromFile();
3627
3628   // Update Python script
3629   // check names of groups
3630   checkGroupNames();
3631   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportDAT( r'" << file << "' )";
3632
3633   // Perform Export
3634   PrepareForWriting(file);
3635   _impl->ExportDAT(file);
3636 }
3637
3638 //================================================================================
3639 /*!
3640  * \brief Export a mesh to an UNV file
3641  */
3642 //================================================================================
3643
3644 void SMESH_Mesh_i::ExportUNV (const char *file)
3645   throw(SALOME::SALOME_Exception)
3646 {
3647   Unexpect aCatch(SALOME_SalomeException);
3648   if ( _preMeshInfo )
3649     _preMeshInfo->FullLoadFromFile();
3650
3651   // Update Python script
3652   // check names of groups
3653   checkGroupNames();
3654   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportUNV( r'" << file << "' )";
3655
3656   // Perform Export
3657   PrepareForWriting(file);
3658   _impl->ExportUNV(file);
3659 }
3660
3661 //================================================================================
3662 /*!
3663  * \brief Export a mesh to an STL file
3664  */
3665 //================================================================================
3666
3667 void SMESH_Mesh_i::ExportSTL (const char *file, const bool isascii)
3668   throw(SALOME::SALOME_Exception)
3669 {
3670   Unexpect aCatch(SALOME_SalomeException);
3671   if ( _preMeshInfo )
3672     _preMeshInfo->FullLoadFromFile();
3673
3674   // Update Python script
3675   // check names of groups
3676   checkGroupNames();
3677   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
3678                 << ".ExportSTL( r'" << file << "', " << isascii << " )";
3679
3680   CORBA::String_var name;
3681   SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( _this() );
3682   if ( !so->_is_nil() )
3683     name = so->GetName();
3684
3685   // Perform Export
3686   PrepareForWriting( file );
3687   _impl->ExportSTL( file, isascii, name.in() );
3688 }
3689
3690 //================================================================================
3691 /*!
3692  * \brief Export a part of mesh to a med file
3693  */
3694 //================================================================================
3695
3696 void SMESH_Mesh_i::ExportPartToMED(SMESH::SMESH_IDSource_ptr meshPart,
3697                                    const char*               file,
3698                                    CORBA::Boolean            auto_groups,
3699                                    CORBA::Long               version,
3700                                    CORBA::Boolean            overwrite,
3701                                    CORBA::Boolean            autoDimension,
3702                                    const GEOM::ListOfFields& fields,
3703                                    const char*               geomAssocFields,
3704                                    CORBA::Double             ZTolerance)
3705   throw (SALOME::SALOME_Exception)
3706 {
3707   MESSAGE("MED version: "<< version);
3708   SMESH_TRY;
3709   if ( _preMeshInfo )
3710     _preMeshInfo->FullLoadFromFile();
3711
3712   // check fields
3713   bool have0dField = false;
3714   if ( fields.length() > 0 )
3715   {
3716     GEOM::GEOM_Object_var shapeToMesh = GetShapeToMesh();
3717     if ( shapeToMesh->_is_nil() )
3718       THROW_SALOME_CORBA_EXCEPTION( "No shape to mesh", SALOME::INTERNAL_ERROR );
3719
3720     for ( size_t i = 0; i < fields.length(); ++i )
3721     {
3722       if ( fields[i]->GetDataType() == GEOM::FDT_String )
3723         THROW_SALOME_CORBA_EXCEPTION
3724           ( "Export of string fields is not supported", SALOME::BAD_PARAM);
3725       GEOM::GEOM_Object_var fieldShape = fields[i]->GetShape();
3726       if ( fieldShape->_is_nil() )
3727         THROW_SALOME_CORBA_EXCEPTION( "Null shape under a field", SALOME::INTERNAL_ERROR );
3728       if ( !fieldShape->IsSame( shapeToMesh ) )
3729         THROW_SALOME_CORBA_EXCEPTION
3730           ( "Field defined not on shape", SALOME::BAD_PARAM);
3731       if ( fields[i]->GetDimension() == 0 )
3732         have0dField = true;
3733     }
3734     if ( geomAssocFields )
3735       for ( int i = 0; geomAssocFields[i]; ++i )
3736         switch ( geomAssocFields[i] ) {
3737         case 'v':case 'e':case 'f':case 's': break;
3738         case 'V':case 'E':case 'F':case 'S': break;
3739         default: THROW_SALOME_CORBA_EXCEPTION
3740             ( "geomAssocFields can include only [vefs] characters", SALOME::BAD_PARAM);
3741         }
3742   }
3743
3744   SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
3745
3746   // write mesh
3747
3748   string aMeshName = "Mesh";
3749   SMESHUtils::Deleter< SMESH_MeshPartDS > tmpDSDeleter(0);
3750   if ( CORBA::is_nil( meshPart ) ||
3751        SMESH::DownCast< SMESH_Mesh_i* >( meshPart ))
3752   {
3753     aMeshName = prepareMeshNameAndGroups(file, overwrite);
3754     _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version,
3755                       0, autoDimension, /*addODOnVertices=*/have0dField,
3756                       ZTolerance);
3757     meshDS = _impl->GetMeshDS();
3758   }
3759   else
3760   {
3761     if ( _preMeshInfo )
3762       _preMeshInfo->FullLoadFromFile();
3763
3764     PrepareForWriting(file, overwrite);
3765
3766     SALOMEDS::SObject_wrap SO = _gen_i->ObjectToSObject( meshPart );
3767     if ( !SO->_is_nil() ) {
3768       CORBA::String_var name = SO->GetName();
3769       aMeshName = name;
3770     }
3771
3772     SMESH_MeshPartDS* partDS = new SMESH_MeshPartDS( meshPart );
3773     _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version,
3774                       partDS, autoDimension, /*addODOnVertices=*/have0dField, ZTolerance);
3775     meshDS = tmpDSDeleter._obj = partDS;
3776   }
3777
3778   // write fields
3779
3780   if ( _impl->HasShapeToMesh() )
3781   {
3782     DriverMED_W_Field fieldWriter;
3783     fieldWriter.SetFile( file );
3784     fieldWriter.SetMeshName( aMeshName );
3785     fieldWriter.AddODOnVertices( have0dField );
3786
3787     exportMEDFields( fieldWriter, meshDS, fields, geomAssocFields );
3788   }
3789
3790   // dump
3791   GEOM::ListOfGBO_var goList = new GEOM::ListOfGBO;
3792   goList->length( fields.length() );
3793   for ( size_t i = 0; i < fields.length(); ++i )
3794   {
3795     GEOM::GEOM_BaseObject_var gbo = GEOM::GEOM_BaseObject::_narrow( fields[i] );
3796     goList[i] = gbo;
3797   }
3798   TPythonDump() << _this() << ".ExportPartToMED( "
3799                 << meshPart << ", r'"
3800                 << file << "', "
3801                 << auto_groups << ", "
3802                 << version << ", "
3803                 << overwrite << ", "
3804                 << autoDimension << ", "
3805                 << goList << ", '"
3806                 << ( geomAssocFields ? geomAssocFields : "" ) << "',"
3807                 << TVar( ZTolerance )
3808                 << " )";
3809
3810   SMESH_CATCH( SMESH::throwCorbaException );
3811 }
3812
3813 //================================================================================
3814 /*!
3815  * Write GEOM fields to MED file
3816  */
3817 //================================================================================
3818
3819 void SMESH_Mesh_i::exportMEDFields( DriverMED_W_Field&        fieldWriter,
3820                                     SMESHDS_Mesh*             meshDS,
3821                                     const GEOM::ListOfFields& fields,
3822                                     const char*               geomAssocFields)
3823 {
3824 #define METH "SMESH_Mesh_i::exportMEDFields() "
3825
3826   if (( fields.length() < 1 ) &&
3827       ( !geomAssocFields || !geomAssocFields[0] ))
3828     return;
3829
3830   std::vector< std::vector< double > > dblVals;
3831   std::vector< std::vector< int > >    intVals;
3832   std::vector< int >                   subIdsByDim[ 4 ];
3833   const double noneDblValue = 0.;
3834   const double noneIntValue = 0;
3835
3836   for ( size_t iF = 0; iF < fields.length(); ++iF )
3837   {
3838     // set field data
3839
3840     int dim = fields[ iF ]->GetDimension();
3841     SMDSAbs_ElementType elemType;
3842     TopAbs_ShapeEnum    shapeType;
3843     switch ( dim ) {
3844     case 0: elemType = SMDSAbs_0DElement; shapeType = TopAbs_VERTEX; break;
3845     case 1: elemType = SMDSAbs_Edge;      shapeType = TopAbs_EDGE;   break;
3846     case 2: elemType = SMDSAbs_Face;      shapeType = TopAbs_FACE;   break;
3847     case 3: elemType = SMDSAbs_Volume;    shapeType = TopAbs_SOLID;  break;
3848     default:
3849       continue; // skip fields on whole shape
3850     }
3851     GEOM::field_data_type dataType = fields[ iF ]->GetDataType();
3852     if ( dataType == GEOM::FDT_String )
3853       continue;
3854     GEOM::ListOfLong_var stepIDs = fields[ iF ]->GetSteps();
3855     if ( stepIDs->length() < 1 )
3856       continue;
3857     GEOM::string_array_var comps = fields[ iF ]->GetComponents();
3858     if ( comps->length() < 1 )
3859       continue;
3860     CORBA::String_var       name = fields[ iF ]->GetName();
3861
3862     if ( !fieldWriter.Set( meshDS,
3863                            name.in(),
3864                            elemType,
3865                            comps->length(),
3866                            /*isIntData=*/false ))//( dataType == GEOM::FDT_Int )))
3867       continue;
3868
3869     for ( size_t iC = 0; iC < comps->length(); ++iC )
3870       fieldWriter.SetCompName( iC, comps[ iC ].in() );
3871
3872     dblVals.resize( comps->length() );
3873     intVals.resize( comps->length() );
3874
3875     // find sub-shape IDs
3876
3877     std::vector< int >& subIds = subIdsByDim[ dim ];
3878     if ( subIds.empty() )
3879       for ( int id = 1; id <= meshDS->MaxShapeIndex(); ++id )
3880         if ( meshDS->IndexToShape( id ).ShapeType() == shapeType )
3881           subIds.push_back( id );
3882
3883     // write steps
3884
3885     SMDS_ElemIteratorPtr elemIt = fieldWriter.GetOrderedElems();
3886     if ( !elemIt )
3887       continue;
3888
3889     for ( size_t iS = 0; iS < stepIDs->length(); ++iS )
3890     {
3891       GEOM::GEOM_FieldStep_var step = fields[ iF ]->GetStep( stepIDs[ iS ]);
3892       if ( step->_is_nil() )
3893         continue;
3894
3895       CORBA::Long stamp = step->GetStamp();
3896       CORBA::Long id    = step->GetID();
3897       fieldWriter.SetDtIt( int( stamp ), int( id ));
3898
3899       // fill dblVals or intVals
3900       for ( size_t iC = 0; iC < comps->length(); ++iC )
3901         if ( dataType == GEOM::FDT_Double )
3902         {
3903           dblVals[ iC ].clear();
3904           dblVals[ iC ].resize( meshDS->MaxShapeIndex()+1, 0 );
3905         }
3906         else
3907         {
3908           intVals[ iC ].clear();
3909           intVals[ iC ].resize( meshDS->MaxShapeIndex()+1, 0 );
3910         }
3911       switch ( dataType )
3912       {
3913       case GEOM::FDT_Double:
3914       {
3915         GEOM::GEOM_DoubleFieldStep_var dblStep = GEOM::GEOM_DoubleFieldStep::_narrow( step );
3916         if ( dblStep->_is_nil() ) continue;
3917         GEOM::ListOfDouble_var vv = dblStep->GetValues();
3918         if ( vv->length() != subIds.size() * comps->length() )
3919           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
3920         for ( size_t iS = 0, iV = 0; iS < subIds.size(); ++iS )
3921           for ( size_t iC = 0; iC < comps->length(); ++iC )
3922             dblVals[ iC ][ subIds[ iS ]] = vv[ iV++ ];
3923         break;
3924       }
3925       case GEOM::FDT_Int:
3926       {
3927         GEOM::GEOM_IntFieldStep_var intStep = GEOM::GEOM_IntFieldStep::_narrow( step );
3928         if ( intStep->_is_nil() ) continue;
3929         GEOM::ListOfLong_var vv = intStep->GetValues();
3930         if ( vv->length() != subIds.size() * comps->length() )
3931           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
3932         for ( size_t iS = 0, iV = 0; iS < subIds.size(); ++iS )
3933           for ( size_t iC = 0; iC < comps->length(); ++iC )
3934             intVals[ iC ][ subIds[ iS ]] = (int) vv[ iV++ ];
3935         break;
3936       }
3937       case GEOM::FDT_Bool:
3938       {
3939         GEOM::GEOM_BoolFieldStep_var boolStep = GEOM::GEOM_BoolFieldStep::_narrow( step );
3940         if ( boolStep->_is_nil() ) continue;
3941         GEOM::short_array_var vv = boolStep->GetValues();
3942         if ( vv->length() != subIds.size() * comps->length() )
3943           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
3944         for ( size_t iS = 0, iV = 0; iS < subIds.size(); ++iS )
3945           for ( size_t iC = 0; iC < comps->length(); ++iC )
3946             intVals[ iC ][ subIds[ iS ]] = (int) vv[ iV++ ];
3947         break;
3948       }
3949       default: continue;
3950       }
3951
3952       // pass values to fieldWriter
3953       elemIt = fieldWriter.GetOrderedElems();
3954       if ( dataType == GEOM::FDT_Double )
3955         while ( elemIt->more() )
3956         {
3957           const SMDS_MeshElement* e = elemIt->next();
3958           const int shapeID = e->getshapeId();
3959           if ( shapeID < 1 || shapeID >= (int) dblVals[0].size() )
3960             for ( size_t iC = 0; iC < comps->length(); ++iC )
3961               fieldWriter.AddValue( noneDblValue );
3962           else
3963             for ( size_t iC = 0; iC < comps->length(); ++iC )
3964               fieldWriter.AddValue( dblVals[ iC ][ shapeID ]);
3965         }
3966       else
3967         while ( elemIt->more() )
3968         {
3969           const SMDS_MeshElement* e = elemIt->next();
3970           const int shapeID = e->getshapeId();
3971           if ( shapeID < 1 || shapeID >= (int) intVals[0].size() )
3972             for ( size_t iC = 0; iC < comps->length(); ++iC )
3973               fieldWriter.AddValue( (double) noneIntValue );
3974           else
3975             for ( size_t iC = 0; iC < comps->length(); ++iC )
3976               fieldWriter.AddValue( (double) intVals[ iC ][ shapeID ]);
3977         }
3978
3979       // write a step
3980       fieldWriter.Perform();
3981       SMESH_ComputeErrorPtr res = fieldWriter.GetError();
3982       if ( res && res->IsKO() )
3983       {
3984         if ( res->myComment.empty() )
3985         { THROW_SALOME_CORBA_EXCEPTION( METH "Fatal error", SALOME::INTERNAL_ERROR ); }
3986         else
3987         { THROW_SALOME_CORBA_EXCEPTION( res->myComment.c_str(), SALOME::INTERNAL_ERROR ); }
3988       }
3989
3990     } // loop on steps
3991   } // loop on fields
3992
3993   if ( !geomAssocFields || !geomAssocFields[0] )
3994     return;
3995
3996   // write geomAssocFields
3997
3998   std::vector< int > shapeDim( TopAbs_SHAPE + 1 );
3999   shapeDim[ TopAbs_COMPOUND  ] = 3;
4000   shapeDim[ TopAbs_COMPSOLID ] = 3;
4001   shapeDim[ TopAbs_SOLID     ] = 3;
4002   shapeDim[ TopAbs_SHELL     ] = 2;
4003   shapeDim[ TopAbs_FACE      ] = 2;
4004   shapeDim[ TopAbs_WIRE      ] = 1;
4005   shapeDim[ TopAbs_EDGE      ] = 1;
4006   shapeDim[ TopAbs_VERTEX    ] = 0;
4007   shapeDim[ TopAbs_SHAPE     ] = 3;
4008
4009   for ( int iF = 0; geomAssocFields[ iF ]; ++iF )
4010   {
4011     std::vector< std::string > compNames;
4012     switch ( geomAssocFields[ iF ]) {
4013     case 'v': case 'V':
4014       fieldWriter.Set( meshDS, "_vertices_", SMDSAbs_Node, /*nbComps=*/2, /*isInt=*/false );
4015       compNames.push_back( "dim" );
4016       break;
4017     case 'e': case 'E':
4018       fieldWriter.Set( meshDS, "_edges_", SMDSAbs_Edge, /*nbComps=*/1, /*isInt=*/false );
4019       break;
4020     case 'f': case 'F':
4021       fieldWriter.Set( meshDS, "_faces_", SMDSAbs_Face, /*nbComps=*/1, /*isInt=*/false );
4022       break;
4023     case 's': case 'S':
4024       fieldWriter.Set( meshDS, "_solids_", SMDSAbs_Volume, /*nbComps=*/1, /*isInt=*/false );
4025       break;
4026     default: continue;
4027     }
4028     compNames.push_back( "id" );
4029     for ( size_t iC = 0; iC < compNames.size(); ++iC )
4030       fieldWriter.SetCompName( iC, compNames[ iC ].c_str() );
4031
4032     fieldWriter.SetDtIt( -1, -1 );
4033
4034     SMDS_ElemIteratorPtr elemIt = fieldWriter.GetOrderedElems();
4035     if ( !elemIt )
4036       continue;
4037
4038     if ( compNames.size() == 2 ) // _vertices_
4039       while ( elemIt->more() )
4040       {
4041         const SMDS_MeshElement* e = elemIt->next();
4042         const int shapeID = e->getshapeId();
4043         if ( shapeID < 1 )
4044         {
4045           fieldWriter.AddValue( (double) -1 );
4046           fieldWriter.AddValue( (double) -1 );
4047         }
4048         else
4049         {
4050           const TopoDS_Shape& S = meshDS->IndexToShape( shapeID );
4051           fieldWriter.AddValue( (double) ( S.IsNull() ? -1 : shapeDim[ S.ShapeType() ]));
4052           fieldWriter.AddValue( (double) shapeID );
4053         }
4054       }
4055     else
4056       while ( elemIt->more() )
4057       {
4058         const SMDS_MeshElement* e = elemIt->next();
4059         const int shapeID = e->getshapeId();
4060         if ( shapeID < 1 )
4061           fieldWriter.AddValue( (double) -1 );
4062         else
4063           fieldWriter.AddValue( (double) shapeID );
4064       }
4065
4066     // write a step
4067     fieldWriter.Perform();
4068     SMESH_ComputeErrorPtr res = fieldWriter.GetError();
4069     if ( res && res->IsKO() )
4070     {
4071       if ( res->myComment.empty() )
4072       { THROW_SALOME_CORBA_EXCEPTION( METH "Fatal error", SALOME::INTERNAL_ERROR ); }
4073       else
4074       { THROW_SALOME_CORBA_EXCEPTION( res->myComment.c_str(), SALOME::INTERNAL_ERROR ); }
4075     }
4076
4077   } // loop on geomAssocFields
4078
4079 #undef METH
4080 }
4081
4082 //================================================================================
4083 /*!
4084  * \brief Export a part of mesh to a DAT file
4085  */
4086 //================================================================================
4087
4088 void SMESH_Mesh_i::ExportPartToDAT(::SMESH::SMESH_IDSource_ptr meshPart,
4089                                    const char*                 file)
4090   throw (SALOME::SALOME_Exception)
4091 {
4092   Unexpect aCatch(SALOME_SalomeException);
4093   if ( _preMeshInfo )
4094     _preMeshInfo->FullLoadFromFile();
4095
4096   PrepareForWriting(file);
4097
4098   SMESH_MeshPartDS partDS( meshPart );
4099   _impl->ExportDAT(file,&partDS);
4100
4101   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
4102                 << ".ExportPartToDAT( " << meshPart << ", r'" << file << "' )";
4103 }
4104 //================================================================================
4105 /*!
4106  * \brief Export a part of mesh to an UNV file
4107  */
4108 //================================================================================
4109
4110 void SMESH_Mesh_i::ExportPartToUNV(::SMESH::SMESH_IDSource_ptr meshPart,
4111                                    const char*                 file)
4112   throw (SALOME::SALOME_Exception)
4113 {
4114   Unexpect aCatch(SALOME_SalomeException);
4115   if ( _preMeshInfo )
4116     _preMeshInfo->FullLoadFromFile();
4117
4118   PrepareForWriting(file);
4119
4120   SMESH_MeshPartDS partDS( meshPart );
4121   _impl->ExportUNV(file, &partDS);
4122
4123   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
4124                 << ".ExportPartToUNV( " << meshPart<< ", r'" << file << "' )";
4125 }
4126 //================================================================================
4127 /*!
4128  * \brief Export a part of mesh to an STL file
4129  */
4130 //================================================================================
4131
4132 void SMESH_Mesh_i::ExportPartToSTL(::SMESH::SMESH_IDSource_ptr meshPart,
4133                                    const char*                 file,
4134                                    ::CORBA::Boolean            isascii)
4135   throw (SALOME::SALOME_Exception)
4136 {
4137   Unexpect aCatch(SALOME_SalomeException);
4138   if ( _preMeshInfo )
4139     _preMeshInfo->FullLoadFromFile();
4140
4141   PrepareForWriting(file);
4142
4143   CORBA::String_var name;
4144   SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( meshPart );
4145   if ( !so->_is_nil() )
4146     name = so->GetName();
4147
4148   SMESH_MeshPartDS partDS( meshPart );
4149   _impl->ExportSTL( file, isascii, name.in(), &partDS );
4150
4151   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportPartToSTL( "
4152                 << meshPart<< ", r'" << file << "', " << isascii << ")";
4153 }
4154
4155 //================================================================================
4156 /*!
4157  * \brief Export a part of mesh to an STL file
4158  */
4159 //================================================================================
4160
4161 void SMESH_Mesh_i::ExportCGNS(::SMESH::SMESH_IDSource_ptr meshPart,
4162                               const char*                 file,
4163                               CORBA::Boolean              overwrite,
4164                               CORBA::Boolean              groupElemsByType)
4165   throw (SALOME::SALOME_Exception)
4166 {
4167 #ifdef WITH_CGNS
4168   Unexpect aCatch(SALOME_SalomeException);
4169   if ( _preMeshInfo )
4170     _preMeshInfo->FullLoadFromFile();
4171
4172   PrepareForWriting(file,overwrite);
4173
4174   std::string meshName("");
4175   SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( meshPart );
4176   if ( !so->_is_nil() )
4177   {
4178     CORBA::String_var name = so->GetName();
4179     meshName = name.in();
4180   }
4181   SMESH_TRY;
4182
4183   SMESH_MeshPartDS partDS( meshPart );
4184   _impl->ExportCGNS(file, &partDS, meshName.c_str(), groupElemsByType );
4185
4186   SMESH_CATCH( SMESH::throwCorbaException );
4187
4188   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportCGNS( "
4189                 << meshPart<< ", r'" << file << "', " << overwrite << ")";
4190 #else
4191   THROW_SALOME_CORBA_EXCEPTION("CGNS library is unavailable", SALOME::INTERNAL_ERROR);
4192 #endif
4193 }
4194
4195 //================================================================================
4196 /*!
4197  * \brief Export a part of mesh to a GMF file
4198  */
4199 //================================================================================
4200
4201 void SMESH_Mesh_i::ExportGMF(::SMESH::SMESH_IDSource_ptr meshPart,
4202                              const char*                 file,
4203                              bool                        withRequiredGroups)
4204   throw (SALOME::SALOME_Exception)
4205 {
4206   Unexpect aCatch(SALOME_SalomeException);
4207   if ( _preMeshInfo )
4208     _preMeshInfo->FullLoadFromFile();
4209
4210   PrepareForWriting(file,/*overwrite=*/true);
4211
4212   SMESH_MeshPartDS partDS( meshPart );
4213   _impl->ExportGMF(file, &partDS, withRequiredGroups);
4214
4215   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportGMF( "
4216                 << meshPart<< ", r'"
4217                 << file << "', "
4218                 << withRequiredGroups << ")";
4219 }
4220
4221 //=============================================================================
4222 /*!
4223  * Return computation progress [0.,1]
4224  */
4225 //=============================================================================
4226
4227 CORBA::Double SMESH_Mesh_i::GetComputeProgress()
4228 {
4229   SMESH_TRY;
4230
4231   return _impl->GetComputeProgress();
4232
4233   SMESH_CATCH( SMESH::doNothing );
4234   return 0.;
4235 }
4236
4237 CORBA::Long SMESH_Mesh_i::NbNodes()throw(SALOME::SALOME_Exception)
4238 {
4239   Unexpect aCatch(SALOME_SalomeException);
4240   if ( _preMeshInfo )
4241     return _preMeshInfo->NbNodes();
4242
4243   return _impl->NbNodes();
4244 }
4245
4246 CORBA::Long SMESH_Mesh_i::NbElements()throw (SALOME::SALOME_Exception)
4247 {
4248   Unexpect aCatch(SALOME_SalomeException);
4249   if ( _preMeshInfo )
4250     return _preMeshInfo->NbElements();
4251
4252   return Nb0DElements() + NbEdges() + NbFaces() + NbVolumes() + NbBalls();
4253 }
4254
4255 CORBA::Long SMESH_Mesh_i::Nb0DElements()throw (SALOME::SALOME_Exception)
4256 {
4257   Unexpect aCatch(SALOME_SalomeException);
4258   if ( _preMeshInfo )
4259     return _preMeshInfo->Nb0DElements();
4260
4261   return _impl->Nb0DElements();
4262 }
4263
4264 CORBA::Long SMESH_Mesh_i::NbBalls() throw (SALOME::SALOME_Exception)
4265 {
4266   Unexpect aCatch(SALOME_SalomeException);
4267   if ( _preMeshInfo )
4268     return _preMeshInfo->NbBalls();
4269
4270   return _impl->NbBalls();
4271 }
4272
4273 CORBA::Long SMESH_Mesh_i::NbEdges()throw(SALOME::SALOME_Exception)
4274 {
4275   Unexpect aCatch(SALOME_SalomeException);
4276   if ( _preMeshInfo )
4277     return _preMeshInfo->NbEdges();
4278
4279   return _impl->NbEdges();
4280 }
4281
4282 CORBA::Long SMESH_Mesh_i::NbEdgesOfOrder(SMESH::ElementOrder order)
4283   throw(SALOME::SALOME_Exception)
4284 {
4285   Unexpect aCatch(SALOME_SalomeException);
4286   if ( _preMeshInfo )
4287     return _preMeshInfo->NbEdges( (SMDSAbs_ElementOrder) order );
4288
4289   return _impl->NbEdges( (SMDSAbs_ElementOrder) order);
4290 }
4291
4292 //=============================================================================
4293
4294 CORBA::Long SMESH_Mesh_i::NbFaces()throw(SALOME::SALOME_Exception)
4295 {
4296   Unexpect aCatch(SALOME_SalomeException);
4297   if ( _preMeshInfo )
4298     return _preMeshInfo->NbFaces();
4299
4300   return _impl->NbFaces();
4301 }
4302
4303 CORBA::Long SMESH_Mesh_i::NbTriangles()throw(SALOME::SALOME_Exception)
4304 {
4305   Unexpect aCatch(SALOME_SalomeException);
4306   if ( _preMeshInfo )
4307     return _preMeshInfo->NbTriangles();
4308
4309   return _impl->NbTriangles();
4310 }
4311
4312 CORBA::Long SMESH_Mesh_i::NbBiQuadTriangles()throw(SALOME::SALOME_Exception)
4313 {
4314   Unexpect aCatch(SALOME_SalomeException);
4315   if ( _preMeshInfo )
4316     return _preMeshInfo->NbBiQuadTriangles();
4317
4318   return _impl->NbBiQuadTriangles();
4319 }
4320
4321 CORBA::Long SMESH_Mesh_i::NbQuadrangles()throw(SALOME::SALOME_Exception)
4322 {
4323   Unexpect aCatch(SALOME_SalomeException);
4324   if ( _preMeshInfo )
4325     return _preMeshInfo->NbQuadrangles();
4326
4327   return _impl->NbQuadrangles();
4328 }
4329
4330 CORBA::Long SMESH_Mesh_i::NbBiQuadQuadrangles()throw(SALOME::SALOME_Exception)
4331 {
4332   Unexpect aCatch(SALOME_SalomeException);
4333   if ( _preMeshInfo )
4334     return _preMeshInfo->NbBiQuadQuadrangles();
4335
4336   return _impl->NbBiQuadQuadrangles();
4337 }
4338
4339 CORBA::Long SMESH_Mesh_i::NbPolygons() throw(SALOME::SALOME_Exception)
4340 {
4341   Unexpect aCatch(SALOME_SalomeException);
4342   if ( _preMeshInfo )
4343     return _preMeshInfo->NbPolygons();
4344
4345   return _impl->NbPolygons();
4346 }
4347
4348 CORBA::Long SMESH_Mesh_i::NbPolygonsOfOrder(SMESH::ElementOrder order) throw(SALOME::SALOME_Exception)
4349 {
4350   Unexpect aCatch(SALOME_SalomeException);
4351   if ( _preMeshInfo )
4352     return _preMeshInfo->NbPolygons((SMDSAbs_ElementOrder) order);
4353
4354   return _impl->NbPolygons((SMDSAbs_ElementOrder)order);
4355 }
4356
4357 CORBA::Long SMESH_Mesh_i::NbFacesOfOrder(SMESH::ElementOrder order)
4358   throw(SALOME::SALOME_Exception)
4359 {
4360   Unexpect aCatch(SALOME_SalomeException);
4361   if ( _preMeshInfo )
4362     return _preMeshInfo->NbFaces( (SMDSAbs_ElementOrder) order );
4363
4364   return _impl->NbFaces( (SMDSAbs_ElementOrder) order);
4365 }
4366
4367 CORBA::Long SMESH_Mesh_i::NbTrianglesOfOrder(SMESH::ElementOrder order)
4368   throw(SALOME::SALOME_Exception)
4369 {
4370   Unexpect aCatch(SALOME_SalomeException);
4371   if ( _preMeshInfo )
4372     return _preMeshInfo->NbTriangles( (SMDSAbs_ElementOrder) order );
4373
4374   return _impl->NbTriangles( (SMDSAbs_ElementOrder) order);
4375 }
4376
4377 CORBA::Long SMESH_Mesh_i::NbQuadranglesOfOrder(SMESH::ElementOrder order)
4378   throw(SALOME::SALOME_Exception)
4379 {
4380   Unexpect aCatch(SALOME_SalomeException);
4381   if ( _preMeshInfo )
4382     return _preMeshInfo->NbQuadrangles( (SMDSAbs_ElementOrder) order );
4383
4384   return _impl->NbQuadrangles( (SMDSAbs_ElementOrder) order);
4385 }
4386
4387 //=============================================================================
4388
4389 CORBA::Long SMESH_Mesh_i::NbVolumes()throw(SALOME::SALOME_Exception)
4390 {
4391   Unexpect aCatch(SALOME_SalomeException);
4392   if ( _preMeshInfo )
4393     return _preMeshInfo->NbVolumes();
4394
4395   return _impl->NbVolumes();
4396 }
4397
4398 CORBA::Long SMESH_Mesh_i::NbTetras()throw(SALOME::SALOME_Exception)
4399 {
4400   Unexpect aCatch(SALOME_SalomeException);
4401   if ( _preMeshInfo )
4402     return _preMeshInfo->NbTetras();
4403
4404   return _impl->NbTetras();
4405 }
4406
4407 CORBA::Long SMESH_Mesh_i::NbHexas()throw(SALOME::SALOME_Exception)
4408 {
4409   Unexpect aCatch(SALOME_SalomeException);
4410   if ( _preMeshInfo )
4411     return _preMeshInfo->NbHexas();
4412
4413   return _impl->NbHexas();
4414 }
4415
4416 CORBA::Long SMESH_Mesh_i::NbTriQuadraticHexas()throw(SALOME::SALOME_Exception)
4417 {
4418   Unexpect aCatch(SALOME_SalomeException);
4419   if ( _preMeshInfo )
4420     return _preMeshInfo->NbTriQuadHexas();
4421
4422   return _impl->NbTriQuadraticHexas();
4423 }
4424
4425 CORBA::Long SMESH_Mesh_i::NbPyramids()throw(SALOME::SALOME_Exception)
4426 {
4427   Unexpect aCatch(SALOME_SalomeException);
4428   if ( _preMeshInfo )
4429     return _preMeshInfo->NbPyramids();
4430
4431   return _impl->NbPyramids();
4432 }
4433
4434 CORBA::Long SMESH_Mesh_i::NbPrisms()throw(SALOME::SALOME_Exception)
4435 {
4436   Unexpect aCatch(SALOME_SalomeException);
4437   if ( _preMeshInfo )
4438     return _preMeshInfo->NbPrisms();
4439
4440   return _impl->NbPrisms();
4441 }
4442
4443 CORBA::Long SMESH_Mesh_i::NbHexagonalPrisms()throw(SALOME::SALOME_Exception)
4444 {
4445   Unexpect aCatch(SALOME_SalomeException);
4446   if ( _preMeshInfo )
4447     return _preMeshInfo->NbHexPrisms();
4448
4449   return _impl->NbHexagonalPrisms();
4450 }
4451
4452 CORBA::Long SMESH_Mesh_i::NbPolyhedrons()throw(SALOME::SALOME_Exception)
4453 {
4454   Unexpect aCatch(SALOME_SalomeException);
4455   if ( _preMeshInfo )
4456     return _preMeshInfo->NbPolyhedrons();
4457
4458   return _impl->NbPolyhedrons();
4459 }
4460
4461 CORBA::Long SMESH_Mesh_i::NbVolumesOfOrder(SMESH::ElementOrder order)
4462   throw(SALOME::SALOME_Exception)
4463 {
4464   Unexpect aCatch(SALOME_SalomeException);
4465   if ( _preMeshInfo )
4466     return _preMeshInfo->NbVolumes( (SMDSAbs_ElementOrder) order );
4467
4468   return _impl->NbVolumes( (SMDSAbs_ElementOrder) order);
4469 }
4470
4471 CORBA::Long SMESH_Mesh_i::NbTetrasOfOrder(SMESH::ElementOrder order)
4472   throw(SALOME::SALOME_Exception)
4473 {
4474   Unexpect aCatch(SALOME_SalomeException);
4475   if ( _preMeshInfo )
4476     return _preMeshInfo->NbTetras( (SMDSAbs_ElementOrder) order);
4477
4478   return _impl->NbTetras( (SMDSAbs_ElementOrder) order);
4479 }
4480
4481 CORBA::Long SMESH_Mesh_i::NbHexasOfOrder(SMESH::ElementOrder order)
4482   throw(SALOME::SALOME_Exception)
4483 {
4484   Unexpect aCatch(SALOME_SalomeException);
4485   if ( _preMeshInfo )
4486     return _preMeshInfo->NbHexas( (SMDSAbs_ElementOrder) order);
4487
4488   return _impl->NbHexas( (SMDSAbs_ElementOrder) order);
4489 }
4490
4491 CORBA::Long SMESH_Mesh_i::NbPyramidsOfOrder(SMESH::ElementOrder order)
4492   throw(SALOME::SALOME_Exception)
4493 {
4494   Unexpect aCatch(SALOME_SalomeException);
4495   if ( _preMeshInfo )
4496     return _preMeshInfo->NbPyramids( (SMDSAbs_ElementOrder) order);
4497
4498   return _impl->NbPyramids( (SMDSAbs_ElementOrder) order);
4499 }
4500
4501 CORBA::Long SMESH_Mesh_i::NbPrismsOfOrder(SMESH::ElementOrder order)
4502   throw(SALOME::SALOME_Exception)
4503 {
4504   Unexpect aCatch(SALOME_SalomeException);
4505   if ( _preMeshInfo )
4506     return _preMeshInfo->NbPrisms( (SMDSAbs_ElementOrder) order);
4507
4508   return _impl->NbPrisms( (SMDSAbs_ElementOrder) order);
4509 }
4510
4511 //=============================================================================
4512 /*!
4513  * Returns nb of published sub-meshes
4514  */
4515 //=============================================================================
4516
4517 CORBA::Long SMESH_Mesh_i::NbSubMesh()throw(SALOME::SALOME_Exception)
4518 {
4519   Unexpect aCatch(SALOME_SalomeException);
4520   return _mapSubMesh_i.size();
4521 }
4522
4523 //=============================================================================
4524 /*!
4525  * Dumps mesh into a string
4526  */
4527 //=============================================================================
4528
4529 char* SMESH_Mesh_i::Dump()
4530 {
4531   ostringstream os;
4532   _impl->Dump( os );
4533   return CORBA::string_dup( os.str().c_str() );
4534 }
4535
4536 //=============================================================================
4537 /*!
4538  * Method of SMESH_IDSource interface
4539  */
4540 //=============================================================================
4541
4542 SMESH::long_array* SMESH_Mesh_i::GetIDs()
4543 {
4544   return GetElementsId();
4545 }
4546
4547 //=============================================================================
4548 /*!
4549  * Returns ids of all elements
4550  */
4551 //=============================================================================
4552
4553 SMESH::long_array* SMESH_Mesh_i::GetElementsId()
4554   throw (SALOME::SALOME_Exception)
4555 {
4556   Unexpect aCatch(SALOME_SalomeException);
4557   if ( _preMeshInfo )
4558     _preMeshInfo->FullLoadFromFile();
4559
4560   SMESH::long_array_var aResult = new SMESH::long_array();
4561   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
4562
4563   if ( aSMESHDS_Mesh == NULL )
4564     return aResult._retn();
4565
4566   long nbElements = NbElements();
4567   aResult->length( nbElements );
4568   SMDS_ElemIteratorPtr anIt = aSMESHDS_Mesh->elementsIterator();
4569   for ( int i = 0, n = nbElements; i < n && anIt->more(); i++ )
4570     aResult[i] = anIt->next()->GetID();
4571
4572   return aResult._retn();
4573 }
4574
4575
4576 //=============================================================================
4577 /*!
4578  * Returns ids of all elements of given type
4579  */
4580 //=============================================================================
4581
4582 SMESH::long_array* SMESH_Mesh_i::GetElementsByType( SMESH::ElementType theElemType )
4583     throw (SALOME::SALOME_Exception)
4584 {
4585   Unexpect aCatch(SALOME_SalomeException);
4586   if ( _preMeshInfo )
4587     _preMeshInfo->FullLoadFromFile();
4588
4589   SMESH::long_array_var aResult = new SMESH::long_array();
4590   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
4591
4592   if ( aSMESHDS_Mesh == NULL )
4593     return aResult._retn();
4594
4595   long nbElements = NbElements();
4596
4597   // No sense in returning ids of elements along with ids of nodes:
4598   // when theElemType == SMESH::ALL, return node ids only if
4599   // there are no elements
4600   if ( theElemType == SMESH::NODE || (theElemType == SMESH::ALL && nbElements == 0) )
4601     return GetNodesId();
4602
4603   aResult->length( nbElements );
4604
4605   int i = 0;
4606
4607   SMDS_ElemIteratorPtr anIt = aSMESHDS_Mesh->elementsIterator( (SMDSAbs_ElementType)theElemType );
4608   while ( i < nbElements && anIt->more() )
4609     aResult[i++] = anIt->next()->GetID();
4610
4611   aResult->length( i );
4612
4613   return aResult._retn();
4614 }
4615
4616 //=============================================================================
4617 /*!
4618  * Returns ids of all nodes
4619  */
4620 //=============================================================================
4621
4622 SMESH::long_array* SMESH_Mesh_i::GetNodesId()
4623   throw (SALOME::SALOME_Exception)
4624 {
4625   Unexpect aCatch(SALOME_SalomeException);
4626   if ( _preMeshInfo )
4627     _preMeshInfo->FullLoadFromFile();
4628
4629   SMESH::long_array_var aResult = new SMESH::long_array();
4630   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
4631
4632   if ( aMeshDS == NULL )
4633     return aResult._retn();
4634
4635   long nbNodes = NbNodes();
4636   aResult->length( nbNodes );
4637   SMDS_NodeIteratorPtr anIt = aMeshDS->nodesIterator();
4638   for ( int i = 0, n = nbNodes; i < n && anIt->more(); i++ )
4639     aResult[i] = anIt->next()->GetID();
4640
4641   return aResult._retn();
4642 }
4643
4644 //=============================================================================
4645 /*!
4646  *
4647  */
4648 //=============================================================================
4649
4650 SMESH::ElementType SMESH_Mesh_i::GetElementType( const CORBA::Long id, const bool iselem )
4651   throw (SALOME::SALOME_Exception)
4652 {
4653   SMESH::ElementType type = SMESH::ALL;
4654   SMESH_TRY;
4655
4656   if ( _preMeshInfo )
4657     _preMeshInfo->FullLoadFromFile();
4658
4659   type = ( SMESH::ElementType ) _impl->GetElementType( id, iselem );
4660
4661   SMESH_CATCH( SMESH::throwCorbaException );
4662
4663   return type;
4664 }
4665
4666 //=============================================================================
4667 /*!
4668  *
4669  */
4670 //=============================================================================
4671
4672 SMESH::EntityType SMESH_Mesh_i::GetElementGeomType( const CORBA::Long id )
4673   throw (SALOME::SALOME_Exception)
4674 {
4675   if ( _preMeshInfo )
4676     _preMeshInfo->FullLoadFromFile();
4677
4678   const SMDS_MeshElement* e = _impl->GetMeshDS()->FindElement(id);
4679   if ( !e )
4680     THROW_SALOME_CORBA_EXCEPTION( "invalid element id", SALOME::BAD_PARAM );
4681
4682   return ( SMESH::EntityType ) e->GetEntityType();
4683 }
4684
4685 //=============================================================================
4686 /*!
4687  *
4688  */
4689 //=============================================================================
4690
4691 SMESH::GeometryType SMESH_Mesh_i::GetElementShape( const CORBA::Long id )
4692   throw (SALOME::SALOME_Exception)
4693 {
4694   if ( _preMeshInfo )
4695     _preMeshInfo->FullLoadFromFile();
4696
4697   const SMDS_MeshElement* e = _impl->GetMeshDS()->FindElement(id);
4698   if ( !e )
4699     THROW_SALOME_CORBA_EXCEPTION( "invalid element id", SALOME::BAD_PARAM );
4700
4701   return ( SMESH::GeometryType ) e->GetGeomType();
4702 }
4703
4704 //=============================================================================
4705 /*!
4706  * Returns ID of elements for given submesh
4707  */
4708 //=============================================================================
4709 SMESH::long_array* SMESH_Mesh_i::GetSubMeshElementsId(const CORBA::Long ShapeID)
4710      throw (SALOME::SALOME_Exception)
4711 {
4712   SMESH::long_array_var aResult = new SMESH::long_array();
4713
4714   SMESH_TRY;
4715   if ( _preMeshInfo )
4716     _preMeshInfo->FullLoadFromFile();
4717
4718   SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID);
4719   if(!SM) return aResult._retn();
4720
4721   SMESHDS_SubMesh* SDSM = SM->GetSubMeshDS();
4722   if(!SDSM) return aResult._retn();
4723
4724   aResult->length(SDSM->NbElements());
4725
4726   SMDS_ElemIteratorPtr eIt = SDSM->GetElements();
4727   int i = 0;
4728   while ( eIt->more() ) {
4729     aResult[i++] = eIt->next()->GetID();
4730   }
4731
4732   SMESH_CATCH( SMESH::throwCorbaException );
4733
4734   return aResult._retn();
4735 }
4736
4737 //=============================================================================
4738 /*!
4739  * Returns ID of nodes for given submesh
4740  * If param all==true - returns all nodes, else -
4741  * returns only nodes on shapes.
4742  */
4743 //=============================================================================
4744
4745 SMESH::long_array* SMESH_Mesh_i::GetSubMeshNodesId(const CORBA::Long ShapeID,
4746                                                    CORBA::Boolean    all)
4747   throw (SALOME::SALOME_Exception)
4748 {
4749   SMESH::long_array_var aResult = new SMESH::long_array();
4750
4751   SMESH_TRY;
4752   if ( _preMeshInfo )
4753     _preMeshInfo->FullLoadFromFile();
4754
4755   SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID);
4756   if(!SM) return aResult._retn();
4757
4758   SMESHDS_SubMesh* SDSM = SM->GetSubMeshDS();
4759   if(!SDSM) return aResult._retn();
4760
4761   set<int> theElems;
4762   if( !all || (SDSM->NbElements()==0) ) { // internal nodes or vertex submesh
4763     SMDS_NodeIteratorPtr nIt = SDSM->GetNodes();
4764     while ( nIt->more() ) {
4765       const SMDS_MeshNode* elem = nIt->next();
4766       theElems.insert( elem->GetID() );
4767     }
4768   }
4769   else { // all nodes of submesh elements
4770     SMDS_ElemIteratorPtr eIt = SDSM->GetElements();
4771     while ( eIt->more() ) {
4772       const SMDS_MeshElement* anElem = eIt->next();
4773       SMDS_ElemIteratorPtr nIt = anElem->nodesIterator();
4774       while ( nIt->more() ) {
4775         const SMDS_MeshElement* elem = nIt->next();
4776         theElems.insert( elem->GetID() );
4777       }
4778     }
4779   }
4780
4781   aResult->length(theElems.size());
4782   set<int>::iterator itElem;
4783   int i = 0;
4784   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
4785     aResult[i++] = *itElem;
4786
4787   SMESH_CATCH( SMESH::throwCorbaException );
4788
4789   return aResult._retn();
4790 }
4791
4792 //=============================================================================
4793 /*!
4794  * Returns type of elements for given submesh
4795  */
4796 //=============================================================================
4797
4798 SMESH::ElementType SMESH_Mesh_i::GetSubMeshElementType(const CORBA::Long ShapeID)
4799   throw (SALOME::SALOME_Exception)
4800 {
4801   SMESH::ElementType type = SMESH::ALL;
4802
4803   SMESH_TRY;
4804   if ( _preMeshInfo )
4805     _preMeshInfo->FullLoadFromFile();
4806
4807   SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID);
4808   if(!SM) return SMESH::ALL;
4809
4810   SMESHDS_SubMesh* SDSM = SM->GetSubMeshDS();
4811   if(!SDSM) return SMESH::ALL;
4812
4813   if(SDSM->NbElements()==0)
4814     return (SM->GetSubShape().ShapeType() == TopAbs_VERTEX) ? SMESH::NODE : SMESH::ALL;
4815
4816   SMDS_ElemIteratorPtr eIt = SDSM->GetElements();
4817   const SMDS_MeshElement* anElem = eIt->next();
4818
4819   type = ( SMESH::ElementType ) anElem->GetType();
4820
4821   SMESH_CATCH( SMESH::throwCorbaException );
4822
4823   return type;
4824 }
4825
4826
4827 //=============================================================================
4828 /*!
4829  * Returns pointer to _impl as an integer value. Is called from constructor of SMESH_Client
4830  */
4831 //=============================================================================
4832
4833 CORBA::LongLong SMESH_Mesh_i::GetMeshPtr()
4834 {
4835   if ( _preMeshInfo )
4836     _preMeshInfo->FullLoadFromFile();
4837
4838   CORBA::LongLong pointeur = CORBA::LongLong(_impl);
4839   if ( MYDEBUG ) MESSAGE("CORBA::LongLong SMESH_Mesh_i::GetMeshPtr() "<<pointeur);
4840   return pointeur;
4841 }
4842
4843
4844 //=============================================================================
4845 /*!
4846  * Get XYZ coordinates of node as list of double
4847  * If there is not node for given ID - returns empty list
4848  */
4849 //=============================================================================
4850
4851 SMESH::double_array* SMESH_Mesh_i::GetNodeXYZ(const CORBA::Long id)
4852 {
4853   if ( _preMeshInfo )
4854     _preMeshInfo->FullLoadFromFile();
4855
4856   SMESH::double_array_var aResult = new SMESH::double_array();
4857   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
4858   if ( aMeshDS == NULL )
4859     return aResult._retn();
4860
4861   // find node
4862   const SMDS_MeshNode* aNode = aMeshDS->FindNode(id);
4863   if(!aNode)
4864     return aResult._retn();
4865
4866   // add coordinates
4867   aResult->length(3);
4868   aResult[0] = aNode->X();
4869   aResult[1] = aNode->Y();
4870   aResult[2] = aNode->Z();
4871   return aResult._retn();
4872 }
4873
4874
4875 //=============================================================================
4876 /*!
4877  * For given node returns list of IDs of inverse elements
4878  * If there is not node for given ID - returns empty list
4879  */
4880 //=============================================================================
4881
4882 SMESH::long_array* SMESH_Mesh_i::GetNodeInverseElements(const CORBA::Long  id,
4883                                                         SMESH::ElementType elemType)
4884 {
4885   if ( _preMeshInfo )
4886     _preMeshInfo->FullLoadFromFile();
4887
4888   SMESH::long_array_var aResult = new SMESH::long_array();
4889   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
4890   if ( aMeshDS == NULL )
4891     return aResult._retn();
4892
4893   // find node
4894   const SMDS_MeshNode* aNode = aMeshDS->FindNode( id );
4895   if ( !aNode )
4896     return aResult._retn();
4897
4898   // find inverse elements
4899   SMDSAbs_ElementType type = SMDSAbs_ElementType( elemType );
4900   SMDS_ElemIteratorPtr eIt = aNode->GetInverseElementIterator( type );
4901   aResult->length( aNode->NbInverseElements( type ));
4902   for( int i = 0; eIt->more(); ++i )
4903   {
4904     const SMDS_MeshElement* elem = eIt->next();
4905     aResult[ i ] = elem->GetID();
4906   }
4907   return aResult._retn();
4908 }
4909
4910 //=============================================================================
4911 /*!
4912  * \brief Return position of a node on shape
4913  */
4914 //=============================================================================
4915
4916 SMESH::NodePosition* SMESH_Mesh_i::GetNodePosition(CORBA::Long NodeID)
4917 {
4918   if ( _preMeshInfo )
4919     _preMeshInfo->FullLoadFromFile();
4920
4921   SMESH::NodePosition* aNodePosition = new SMESH::NodePosition();
4922   aNodePosition->shapeID = 0;
4923   aNodePosition->shapeType = GEOM::SHAPE;
4924
4925   SMESHDS_Mesh* mesh = _impl->GetMeshDS();
4926   if ( !mesh ) return aNodePosition;
4927
4928   if ( const SMDS_MeshNode* aNode = mesh->FindNode(NodeID) )
4929   {
4930     if ( SMDS_PositionPtr pos = aNode->GetPosition() )
4931     {
4932       aNodePosition->shapeID = aNode->getshapeId();
4933       switch ( pos->GetTypeOfPosition() ) {
4934       case SMDS_TOP_EDGE:
4935         aNodePosition->shapeType = GEOM::EDGE;
4936         aNodePosition->params.length(1);
4937         aNodePosition->params[0] = SMDS_EdgePositionPtr( pos )->GetUParameter();
4938         break;
4939       case SMDS_TOP_FACE: {
4940         SMDS_FacePositionPtr fPos = pos;
4941         aNodePosition->shapeType = GEOM::FACE;
4942         aNodePosition->params.length(2);
4943         aNodePosition->params[0] = fPos->GetUParameter();
4944         aNodePosition->params[1] = fPos->GetVParameter();
4945         break;
4946       }
4947       case SMDS_TOP_VERTEX:
4948         aNodePosition->shapeType = GEOM::VERTEX;
4949         break;
4950       case SMDS_TOP_3DSPACE:
4951         if ( TopExp_Explorer(_impl->GetShapeToMesh(), TopAbs_SOLID).More() )
4952           aNodePosition->shapeType = GEOM::SOLID;
4953         else if ( TopExp_Explorer(_impl->GetShapeToMesh(), TopAbs_SHELL).More() )
4954           aNodePosition->shapeType = GEOM::SHELL;
4955         break;
4956       default:;
4957       }
4958     }
4959   }
4960   return aNodePosition;
4961 }
4962
4963 //=============================================================================
4964 /*!
4965  * \brief Return position of an element on shape
4966  */
4967 //=============================================================================
4968
4969 SMESH::ElementPosition SMESH_Mesh_i::GetElementPosition(CORBA::Long ElemID)
4970 {
4971   if ( _preMeshInfo )
4972     _preMeshInfo->FullLoadFromFile();
4973
4974   SMESH::ElementPosition anElementPosition;
4975   anElementPosition.shapeID = 0;
4976   anElementPosition.shapeType = GEOM::SHAPE;
4977
4978   SMESHDS_Mesh* mesh = _impl->GetMeshDS();
4979   if ( !mesh ) return anElementPosition;
4980
4981   if ( const SMDS_MeshElement* anElem = mesh->FindElement( ElemID ) )
4982   {
4983     anElementPosition.shapeID = anElem->getshapeId();
4984     const TopoDS_Shape& aSp = mesh->IndexToShape( anElem->getshapeId() );
4985     if ( !aSp.IsNull() ) {
4986       switch ( aSp.ShapeType() ) {
4987       case TopAbs_EDGE:
4988         anElementPosition.shapeType = GEOM::EDGE;
4989         break;
4990       case TopAbs_FACE:
4991         anElementPosition.shapeType = GEOM::FACE;
4992         break;
4993       case TopAbs_VERTEX:
4994         anElementPosition.shapeType = GEOM::VERTEX;
4995         break;
4996       case TopAbs_SOLID:
4997         anElementPosition.shapeType = GEOM::SOLID;
4998         break;
4999       case TopAbs_SHELL:
5000         anElementPosition.shapeType = GEOM::SHELL;
5001         break;
5002       default:;
5003       }
5004     }
5005   }
5006   return anElementPosition;
5007 }
5008
5009 //=============================================================================
5010 /*!
5011  * If given element is node returns IDs of shape from position
5012  * If there is not node for given ID - returns -1
5013  */
5014 //=============================================================================
5015
5016 CORBA::Long SMESH_Mesh_i::GetShapeID(const CORBA::Long id)
5017 {
5018   if ( _preMeshInfo )
5019     _preMeshInfo->FullLoadFromFile();
5020
5021   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5022   if ( aMeshDS == NULL )
5023     return -1;
5024
5025   // try to find node
5026   const SMDS_MeshNode* aNode = aMeshDS->FindNode(id);
5027   if(aNode) {
5028     return aNode->getshapeId();
5029   }
5030
5031   return -1;
5032 }
5033
5034
5035 //=============================================================================
5036 /*!
5037  * For given element returns ID of result shape after
5038  * ::FindShape() from SMESH_MeshEditor
5039  * If there is not element for given ID - returns -1
5040  */
5041 //=============================================================================
5042
5043 CORBA::Long SMESH_Mesh_i::GetShapeIDForElem(const CORBA::Long id)
5044 {
5045   if ( _preMeshInfo )
5046     _preMeshInfo->FullLoadFromFile();
5047
5048   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5049   if ( aMeshDS == NULL )
5050     return -1;
5051
5052   // try to find element
5053   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5054   if(!elem)
5055     return -1;
5056
5057   ::SMESH_MeshEditor aMeshEditor(_impl);
5058   int index = aMeshEditor.FindShape( elem );
5059   if(index>0)
5060     return index;
5061
5062   return -1;
5063 }
5064
5065
5066 //=============================================================================
5067 /*!
5068  * Returns number of nodes for given element
5069  * If there is not element for given ID - returns -1
5070  */
5071 //=============================================================================
5072
5073 CORBA::Long SMESH_Mesh_i::GetElemNbNodes(const CORBA::Long id)
5074 {
5075   if ( _preMeshInfo )
5076     _preMeshInfo->FullLoadFromFile();
5077
5078   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5079   if ( aMeshDS == NULL ) return -1;
5080   // try to find element
5081   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5082   if(!elem) return -1;
5083   return elem->NbNodes();
5084 }
5085
5086
5087 //=============================================================================
5088 /*!
5089  * Returns ID of node by given index for given element
5090  * If there is not element for given ID - returns -1
5091  * If there is not node for given index - returns -2
5092  */
5093 //=============================================================================
5094
5095 CORBA::Long SMESH_Mesh_i::GetElemNode(const CORBA::Long id, const CORBA::Long index)
5096 {
5097   if ( _preMeshInfo )
5098     _preMeshInfo->FullLoadFromFile();
5099
5100   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5101   if ( aMeshDS == NULL ) return -1;
5102   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5103   if(!elem) return -1;
5104   if( index>=elem->NbNodes() || index<0 ) return -1;
5105   return elem->GetNode(index)->GetID();
5106 }
5107
5108 //=============================================================================
5109 /*!
5110  * Returns IDs of nodes of given element
5111  */
5112 //=============================================================================
5113
5114 SMESH::long_array* SMESH_Mesh_i::GetElemNodes(const CORBA::Long id)
5115 {
5116   if ( _preMeshInfo )
5117     _preMeshInfo->FullLoadFromFile();
5118
5119   SMESH::long_array_var aResult = new SMESH::long_array();
5120   if ( SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS() )
5121   {
5122     if ( const SMDS_MeshElement* elem = aMeshDS->FindElement(id) )
5123     {
5124       aResult->length( elem->NbNodes() );
5125       for ( CORBA::ULong i = 0; i < aResult->length(); ++i )
5126         if ( const SMDS_MeshNode* n = elem->GetNode( i ))
5127           aResult[ i ] = n->GetID();
5128     }
5129   }
5130   return aResult._retn();
5131 }
5132
5133 //=============================================================================
5134 /*!
5135  * Returns true if given node is medium node
5136  * in given quadratic element
5137  */
5138 //=============================================================================
5139
5140 CORBA::Boolean SMESH_Mesh_i::IsMediumNode(const CORBA::Long ide, const CORBA::Long idn)
5141 {
5142   if ( _preMeshInfo )
5143     _preMeshInfo->FullLoadFromFile();
5144
5145   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5146   if ( aMeshDS == NULL ) return false;
5147   // try to find node
5148   const SMDS_MeshNode* aNode = aMeshDS->FindNode(idn);
5149   if(!aNode) return false;
5150   // try to find element
5151   const SMDS_MeshElement* elem = aMeshDS->FindElement(ide);
5152   if(!elem) return false;
5153
5154   return elem->IsMediumNode(aNode);
5155 }
5156
5157
5158 //=============================================================================
5159 /*!
5160  * Returns true if given node is medium node
5161  * in one of quadratic elements
5162  */
5163 //=============================================================================
5164
5165 CORBA::Boolean SMESH_Mesh_i::IsMediumNodeOfAnyElem(const CORBA::Long idn,
5166                                                    SMESH::ElementType theElemType)
5167 {
5168   if ( _preMeshInfo )
5169     _preMeshInfo->FullLoadFromFile();
5170
5171   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5172   if ( aMeshDS == NULL ) return false;
5173
5174   // try to find node
5175   const SMDS_MeshNode* aNode = aMeshDS->FindNode(idn);
5176   if(!aNode) return false;
5177
5178   SMESH_MesherHelper aHelper( *(_impl) );
5179
5180   SMDSAbs_ElementType aType;
5181   if(theElemType==SMESH::EDGE) aType = SMDSAbs_Edge;
5182   else if(theElemType==SMESH::FACE) aType = SMDSAbs_Face;
5183   else if(theElemType==SMESH::VOLUME) aType = SMDSAbs_Volume;
5184   else aType = SMDSAbs_All;
5185
5186   return aHelper.IsMedium(aNode,aType);
5187 }
5188
5189
5190 //=============================================================================
5191 /*!
5192  * Returns number of edges for given element
5193  */
5194 //=============================================================================
5195
5196 CORBA::Long SMESH_Mesh_i::ElemNbEdges(const CORBA::Long id)
5197 {
5198   if ( _preMeshInfo )
5199     _preMeshInfo->FullLoadFromFile();
5200
5201   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5202   if ( aMeshDS == NULL ) return -1;
5203   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5204   if(!elem) return -1;
5205   return elem->NbEdges();
5206 }
5207
5208
5209 //=============================================================================
5210 /*!
5211  * Returns number of faces for given element
5212  */
5213 //=============================================================================
5214
5215 CORBA::Long SMESH_Mesh_i::ElemNbFaces(const CORBA::Long id)
5216 {
5217   if ( _preMeshInfo )
5218     _preMeshInfo->FullLoadFromFile();
5219
5220   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5221   if ( aMeshDS == NULL ) return -1;
5222   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5223   if(!elem) return -1;
5224   return elem->NbFaces();
5225 }
5226
5227 //=======================================================================
5228 //function : GetElemFaceNodes
5229 //purpose  : Returns nodes of given face (counted from zero) for given element.
5230 //=======================================================================
5231
5232 SMESH::long_array* SMESH_Mesh_i::GetElemFaceNodes(CORBA::Long  elemId,
5233                                                   CORBA::Short faceIndex)
5234 {
5235   if ( _preMeshInfo )
5236     _preMeshInfo->FullLoadFromFile();
5237
5238   SMESH::long_array_var aResult = new SMESH::long_array();
5239   if ( SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS() )
5240   {
5241     if ( const SMDS_MeshElement* elem = aMeshDS->FindElement(elemId) )
5242     {
5243       SMDS_VolumeTool vtool( elem, /*skipCentralNodes = */false );
5244       if ( faceIndex < vtool.NbFaces() )
5245       {
5246         aResult->length( vtool.NbFaceNodes( faceIndex ));
5247         const SMDS_MeshNode** nn = vtool.GetFaceNodes( faceIndex );
5248         for ( CORBA::ULong i = 0; i < aResult->length(); ++i )
5249           aResult[ i ] = nn[ i ]->GetID();
5250       }
5251     }
5252   }
5253   return aResult._retn();
5254 }
5255
5256 //=======================================================================
5257 //function : GetFaceNormal
5258 //purpose  : Returns three components of normal of given mesh face.
5259 //=======================================================================
5260
5261 SMESH::double_array* SMESH_Mesh_i::GetFaceNormal(CORBA::Long    elemId,
5262                                                  CORBA::Boolean normalized)
5263 {
5264   if ( _preMeshInfo )
5265     _preMeshInfo->FullLoadFromFile();
5266
5267   SMESH::double_array_var aResult = new SMESH::double_array();
5268
5269   if ( SMESHDS_Mesh* mesh = _impl->GetMeshDS() )
5270   {
5271     gp_XYZ normal;
5272     if ( SMESH_MeshAlgos::FaceNormal( mesh->FindElement(elemId), normal, normalized ))
5273     {
5274       aResult->length( 3 );
5275       aResult[ 0 ] = normal.X();
5276       aResult[ 1 ] = normal.Y();
5277       aResult[ 2 ] = normal.Z();
5278     }
5279   }
5280   return aResult._retn();
5281 }
5282
5283 //=======================================================================
5284 //function : FindElementByNodes
5285 //purpose  : Returns an element based on all given nodes.
5286 //=======================================================================
5287
5288 CORBA::Long SMESH_Mesh_i::FindElementByNodes(const SMESH::long_array& nodes)
5289 {
5290   if ( _preMeshInfo )
5291     _preMeshInfo->FullLoadFromFile();
5292
5293   CORBA::Long elemID(0);
5294   if ( SMESHDS_Mesh* mesh = _impl->GetMeshDS() )
5295   {
5296     vector< const SMDS_MeshNode * > nn( nodes.length() );
5297     for ( CORBA::ULong i = 0; i < nodes.length(); ++i )
5298       if ( !( nn[i] = mesh->FindNode( nodes[i] )))
5299         return elemID;
5300
5301     const SMDS_MeshElement* elem = mesh->FindElement( nn, SMDSAbs_All, /*noMedium=*/false );
5302     if ( !elem && ( _impl->NbEdges  ( ORDER_QUADRATIC ) ||
5303                     _impl->NbFaces  ( ORDER_QUADRATIC ) ||
5304                     _impl->NbVolumes( ORDER_QUADRATIC )))
5305       elem = mesh->FindElement( nn, SMDSAbs_All, /*noMedium=*/true );
5306
5307     if ( elem ) elemID = CORBA::Long( elem->GetID() );
5308   }
5309   return elemID;
5310 }
5311
5312 //================================================================================
5313 /*!
5314  * \brief Return elements including all given nodes.
5315  */
5316 //================================================================================
5317
5318 SMESH::long_array* SMESH_Mesh_i::GetElementsByNodes(const SMESH::long_array& nodes,
5319                                                     SMESH::ElementType       elemType)
5320 {
5321   if ( _preMeshInfo )
5322     _preMeshInfo->FullLoadFromFile();
5323
5324   SMESH::long_array_var result = new SMESH::long_array();
5325
5326   if ( SMESHDS_Mesh* mesh = _impl->GetMeshDS() )
5327   {
5328     vector< const SMDS_MeshNode * > nn( nodes.length() );
5329     for ( CORBA::ULong i = 0; i < nodes.length(); ++i )
5330       nn[i] = mesh->FindNode( nodes[i] );
5331
5332     std::vector<const SMDS_MeshElement *> elems;
5333     mesh->GetElementsByNodes( nn, elems, (SMDSAbs_ElementType) elemType );
5334     result->length( elems.size() );
5335     for ( size_t i = 0; i < elems.size(); ++i )
5336       result[i] = elems[i]->GetID();
5337   }
5338   return result._retn();
5339 }
5340
5341 //=============================================================================
5342 /*!
5343  * Returns true if given element is polygon
5344  */
5345 //=============================================================================
5346
5347 CORBA::Boolean SMESH_Mesh_i::IsPoly(const CORBA::Long id)
5348 {
5349   if ( _preMeshInfo )
5350     _preMeshInfo->FullLoadFromFile();
5351
5352   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5353   if ( aMeshDS == NULL ) return false;
5354   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5355   if(!elem) return false;
5356   return elem->IsPoly();
5357 }
5358
5359
5360 //=============================================================================
5361 /*!
5362  * Returns true if given element is quadratic
5363  */
5364 //=============================================================================
5365
5366 CORBA::Boolean SMESH_Mesh_i::IsQuadratic(const CORBA::Long id)
5367 {
5368   if ( _preMeshInfo )
5369     _preMeshInfo->FullLoadFromFile();
5370
5371   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5372   if ( aMeshDS == NULL ) return false;
5373   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5374   if(!elem) return false;
5375   return elem->IsQuadratic();
5376 }
5377
5378 //=============================================================================
5379 /*!
5380  * Returns diameter of ball discrete element or zero in case of an invalid \a id
5381  */
5382 //=============================================================================
5383
5384 CORBA::Double SMESH_Mesh_i::GetBallDiameter(CORBA::Long id)
5385 {
5386   if ( _preMeshInfo )
5387     _preMeshInfo->FullLoadFromFile();
5388
5389   if ( const SMDS_BallElement* ball =
5390        SMDS_Mesh::DownCast<SMDS_BallElement>( _impl->GetMeshDS()->FindElement( id )))
5391     return ball->GetDiameter();
5392
5393   return 0;
5394 }
5395
5396 //=============================================================================
5397 /*!
5398  * Returns bary center for given element
5399  */
5400 //=============================================================================
5401
5402 SMESH::double_array* SMESH_Mesh_i::BaryCenter(const CORBA::Long id)
5403 {
5404   if ( _preMeshInfo )
5405     _preMeshInfo->FullLoadFromFile();
5406
5407   SMESH::double_array_var aResult = new SMESH::double_array();
5408   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5409   if ( aMeshDS == NULL )
5410     return aResult._retn();
5411
5412   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5413   if(!elem)
5414     return aResult._retn();
5415
5416   if(elem->GetType()==SMDSAbs_Volume) {
5417     SMDS_VolumeTool aTool;
5418     if(aTool.Set(elem)) {
5419       aResult->length(3);
5420       if (!aTool.GetBaryCenter( aResult[0], aResult[1], aResult[2]) )
5421         aResult->length(0);
5422     }
5423   }
5424   else {
5425     SMDS_ElemIteratorPtr anIt = elem->nodesIterator();
5426     int nbn = 0;
5427     double x=0., y=0., z=0.;
5428     for(; anIt->more(); ) {
5429       nbn++;
5430       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>(anIt->next());
5431       x += aNode->X();
5432       y += aNode->Y();
5433       z += aNode->Z();
5434     }
5435     if(nbn>0) {
5436       // add coordinates
5437       aResult->length(3);
5438       aResult[0] = x/nbn;
5439       aResult[1] = y/nbn;
5440       aResult[2] = z/nbn;
5441     }
5442   }
5443
5444   return aResult._retn();
5445 }
5446
5447 //================================================================================
5448 /*!
5449  * \brief Create a group of elements preventing computation of a sub-shape
5450  */
5451 //================================================================================
5452
5453 SMESH::ListOfGroups*
5454 SMESH_Mesh_i::MakeGroupsOfBadInputElements( int         theSubShapeID,
5455                                             const char* theGroupName )
5456   throw ( SALOME::SALOME_Exception )
5457 {
5458   Unexpect aCatch(SALOME_SalomeException);
5459
5460   if ( !theGroupName || strlen( theGroupName) == 0 )
5461     THROW_SALOME_CORBA_EXCEPTION( "empty group name",SALOME::BAD_PARAM );
5462
5463   SMESH::ListOfGroups_var groups = new SMESH::ListOfGroups;
5464   ::SMESH_MeshEditor::ElemFeatures elemType;
5465
5466   // submesh by subshape id
5467   if ( !_impl->HasShapeToMesh() ) theSubShapeID = 1;
5468   if ( SMESH_subMesh * sm = _impl->GetSubMeshContaining( theSubShapeID ))
5469   {
5470     // compute error
5471     SMESH_ComputeErrorPtr error = sm->GetComputeError();
5472     if ( error && error->HasBadElems() )
5473     {
5474       // sort bad elements by type
5475       vector< const SMDS_MeshElement* > elemsByType[ SMDSAbs_NbElementTypes ];
5476       const list<const SMDS_MeshElement*>& badElems =
5477         static_cast<SMESH_BadInputElements*>( error.get() )->myBadElements;
5478       list<const SMDS_MeshElement*>::const_iterator elemIt  = badElems.begin();
5479       list<const SMDS_MeshElement*>::const_iterator elemEnd = badElems.end();
5480       for ( ; elemIt != elemEnd; ++elemIt )
5481       {
5482         const SMDS_MeshElement* elem = *elemIt;
5483         if ( !elem ) continue;
5484
5485         if ( elem->GetID() < 1 )
5486         {
5487           // elem is a temporary element, make a real element
5488           vector< const SMDS_MeshNode* > nodes;
5489           SMDS_NodeIteratorPtr nIt = elem->nodeIterator();
5490           while ( nIt->more() && elem )
5491           {
5492             nodes.push_back( nIt->next() );
5493             if ( nodes.back()->GetID() < 1 )
5494               elem = 0;  // a temporary element on temporary nodes
5495           }
5496           if ( elem )
5497           {
5498             ::SMESH_MeshEditor editor( _impl );
5499             elem = editor.AddElement( nodes, elemType.Init( elem ));
5500           }
5501         }
5502         if ( elem )
5503           elemsByType[ elem->GetType() ].push_back( elem );
5504       }
5505
5506       // how many groups to create?
5507       int nbTypes = 0;
5508       for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
5509         nbTypes += int( !elemsByType[ i ].empty() );
5510       groups->length( nbTypes );
5511
5512       // create groups
5513       for ( int i = 0, iG = -1; i < SMDSAbs_NbElementTypes; ++i )
5514       {
5515         vector< const SMDS_MeshElement* >& elems = elemsByType[ i ];
5516         if ( elems.empty() ) continue;
5517
5518         groups[ ++iG ] = createGroup( SMESH::ElementType(i), theGroupName );
5519         if ( _gen_i->CanPublishInStudy( groups[ iG ] ))
5520         {
5521           SMESH::SMESH_Mesh_var mesh = _this();
5522           SALOMEDS::SObject_wrap aSO =
5523             _gen_i->PublishGroup( mesh, groups[ iG ],
5524                                  GEOM::GEOM_Object::_nil(), theGroupName);
5525         }
5526         SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( groups[ iG ]);
5527         if ( !grp_i ) continue;
5528
5529         if ( SMESHDS_Group*  grpDS = dynamic_cast< SMESHDS_Group* >( grp_i->GetGroupDS() ))
5530           for ( size_t iE = 0; iE < elems.size(); ++iE )
5531             grpDS->SMDSGroup().Add( elems[ iE ]);
5532       }
5533     }
5534   }
5535
5536   return groups._retn();
5537 }
5538
5539 //=============================================================================
5540 /*!
5541  * Create and publish group servants if any groups were imported or created anyhow
5542  */
5543 //=============================================================================
5544
5545 void SMESH_Mesh_i::CreateGroupServants()
5546 {
5547   SMESH::SMESH_Mesh_var aMesh = _this();
5548
5549   set<int> addedIDs;
5550   ::SMESH_Mesh::GroupIteratorPtr groupIt = _impl->GetGroups();
5551   while ( groupIt->more() )
5552   {
5553     ::SMESH_Group* group = groupIt->next();
5554     int             anId = group->GetID();
5555
5556     map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.find(anId);
5557     if ( it != _mapGroups.end() && !CORBA::is_nil( it->second ))
5558       continue;
5559     addedIDs.insert( anId );
5560
5561     SMESH_GroupBase_i* aGroupImpl;
5562     TopoDS_Shape       shape;
5563     if ( SMESHDS_GroupOnGeom* groupOnGeom =
5564          dynamic_cast<SMESHDS_GroupOnGeom*>( group->GetGroupDS() ))
5565     {
5566       aGroupImpl = new SMESH_GroupOnGeom_i( SMESH_Gen_i::GetPOA(), this, anId );
5567       shape      = groupOnGeom->GetShape();
5568     }
5569     else {
5570       aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
5571     }
5572
5573     SMESH::SMESH_GroupBase_var groupVar = aGroupImpl->_this();
5574     _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( groupVar );
5575     aGroupImpl->Register();
5576
5577     // register CORBA object for persistence
5578     int nextId = _gen_i->RegisterObject( groupVar );
5579     if(MYDEBUG) { MESSAGE( "Add group to map with id = "<< nextId); }
5580     else        { nextId = 0; } // avoid "unused variable" warning in release mode
5581
5582     // publishing the groups in the study
5583     GEOM::GEOM_Object_var shapeVar = _gen_i->ShapeToGeomObject( shape );
5584     _gen_i->PublishGroup( aMesh, groupVar, shapeVar, group->GetName());
5585   }
5586   if ( !addedIDs.empty() )
5587   {
5588     // python dump
5589     set<int>::iterator id = addedIDs.begin();
5590     for ( ; id != addedIDs.end(); ++id )
5591     {
5592       map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.find(*id);
5593       int i = std::distance( _mapGroups.begin(), it );
5594       TPythonDump() << it->second << " = " << aMesh << ".GetGroups()[ "<< i << " ]";
5595     }
5596   }
5597 }
5598
5599 //=============================================================================
5600 /*!
5601  * \brief Return true if all sub-meshes are computed OK - to update an icon
5602  */
5603 //=============================================================================
5604
5605 bool SMESH_Mesh_i::IsComputedOK()
5606 {
5607   return _impl->IsComputedOK();
5608 }
5609
5610 //=============================================================================
5611 /*!
5612  * \brief Return groups cantained in _mapGroups by their IDs
5613  */
5614 //=============================================================================
5615
5616 SMESH::ListOfGroups* SMESH_Mesh_i::GetGroups(const list<int>& groupIDs) const
5617 {
5618   int nbGroups = groupIDs.size();
5619   SMESH::ListOfGroups_var aList = new SMESH::ListOfGroups();
5620   aList->length( nbGroups );
5621
5622   list<int>::const_iterator ids = groupIDs.begin();
5623   for ( nbGroups = 0; ids != groupIDs.end(); ++ids )
5624   {
5625     map<int, SMESH::SMESH_GroupBase_ptr>::const_iterator it = _mapGroups.find( *ids );
5626     if ( it != _mapGroups.end() && !CORBA::is_nil( it->second ))
5627       aList[nbGroups++] = SMESH::SMESH_GroupBase::_duplicate( it->second );
5628   }
5629   aList->length( nbGroups );
5630   return aList._retn();
5631 }
5632
5633 //=============================================================================
5634 /*!
5635  * \brief Return information about imported file
5636  */
5637 //=============================================================================
5638
5639 SMESH::MedFileInfo* SMESH_Mesh_i::GetMEDFileInfo()
5640 {
5641   SMESH::MedFileInfo_var res( _medFileInfo );
5642   if ( !res.operator->() ) {
5643     res = new SMESH::MedFileInfo;
5644     res->fileName = "";
5645     res->fileSize = res->major = res->minor = res->release = -1;
5646   }
5647   return res._retn();
5648 }
5649
5650 //=======================================================================
5651 //function : FileInfoToString
5652 //purpose  : Persistence of file info
5653 //=======================================================================
5654
5655 std::string SMESH_Mesh_i::FileInfoToString()
5656 {
5657   std::string s;
5658   if ( &_medFileInfo.in() && _medFileInfo->fileName[0] )
5659   {
5660     s = SMESH_Comment( _medFileInfo->fileSize )
5661       << " " << _medFileInfo->major
5662       << " " << _medFileInfo->minor
5663       << " " << _medFileInfo->release
5664       << " " << _medFileInfo->fileName;
5665   }
5666   return s;
5667 }
5668
5669 //=======================================================================
5670 //function : FileInfoFromString
5671 //purpose  : Persistence of file info
5672 //=======================================================================
5673
5674 void SMESH_Mesh_i::FileInfoFromString(const std::string& info)
5675 {
5676   std::string size, major, minor, release, fileName;
5677   std::istringstream is(info);
5678   is >> size >> major >> minor >> release;
5679   fileName = info.data() + ( size.size()   + 1 +
5680                              major.size()  + 1 +
5681                              minor.size()  + 1 +
5682                              release.size()+ 1 );
5683
5684   _medFileInfo           = new SMESH::MedFileInfo();
5685   _medFileInfo->fileName = fileName.c_str();
5686   _medFileInfo->fileSize = atoi( size.c_str() );
5687   _medFileInfo->major    = atoi( major.c_str() );
5688   _medFileInfo->minor    = atoi( minor.c_str() );
5689   _medFileInfo->release  = atoi( release.c_str() );
5690 }
5691
5692 //=============================================================================
5693 /*!
5694  * \brief Pass names of mesh groups from study to mesh DS
5695  */
5696 //=============================================================================
5697
5698 void SMESH_Mesh_i::checkGroupNames()
5699 {
5700   int nbGrp = NbGroups();
5701   if ( !nbGrp )
5702     return;
5703
5704   SMESH::ListOfGroups* grpList = 0;
5705   // avoid dump of "GetGroups"
5706   {
5707     // store python dump into a local variable inside local scope
5708     SMESH::TPythonDump pDump; // do not delete this line of code
5709     grpList = GetGroups();
5710   }
5711
5712   for ( int gIndx = 0; gIndx < nbGrp; gIndx++ ) {
5713     SMESH::SMESH_GroupBase_ptr aGrp = (*grpList)[ gIndx ];
5714     if ( !aGrp )
5715       continue;
5716     SALOMEDS::SObject_wrap aGrpSO = _gen_i->ObjectToSObject( aGrp );
5717     if ( aGrpSO->_is_nil() )
5718       continue;
5719     // correct name of the mesh group if necessary
5720     const char* guiName = aGrpSO->GetName();
5721     if ( strcmp(guiName, aGrp->GetName()) )
5722       aGrp->SetName( guiName );
5723   }
5724 }
5725
5726 //=============================================================================
5727 /*!
5728  * \brief Sets list of notebook variables used for Mesh operations separated by ":" symbol
5729  */
5730 //=============================================================================
5731 void SMESH_Mesh_i::SetParameters(const char* theParameters)
5732 {
5733   SMESH_Gen_i::GetSMESHGen()->UpdateParameters( CORBA::Object_var( _this() ).in(),
5734                                                 theParameters );
5735 }
5736
5737 //=============================================================================
5738 /*!
5739  * \brief Returns list of notebook variables used for Mesh operations separated by ":" symbol
5740  */
5741 //=============================================================================
5742
5743 char* SMESH_Mesh_i::GetParameters()
5744 {
5745   return SMESH_Gen_i::GetSMESHGen()->GetParameters( SMESH::SMESH_Mesh_var( _this()) );
5746 }
5747
5748 //=============================================================================
5749 /*!
5750  * \brief Returns list of notebook variables used for last Mesh operation
5751  */
5752 //=============================================================================
5753 SMESH::string_array* SMESH_Mesh_i::GetLastParameters()
5754 {
5755   SMESH::string_array_var aResult = new SMESH::string_array();
5756   SMESH_Gen_i *gen = SMESH_Gen_i::GetSMESHGen();
5757   if(gen) {
5758     CORBA::String_var aParameters = GetParameters();
5759     SALOMEDS::ListOfListOfStrings_var aSections = SMESH_Gen_i::getStudyServant()->ParseVariables(aParameters);
5760     if ( aSections->length() > 0 ) {
5761       SALOMEDS::ListOfStrings aVars = aSections[ aSections->length() - 1 ];
5762       aResult->length( aVars.length() );
5763       for ( CORBA::ULong i = 0;i < aVars.length(); i++ )
5764         aResult[i] = CORBA::string_dup( aVars[i] );
5765     }
5766   }
5767   return aResult._retn();
5768 }
5769
5770 //=======================================================================
5771 //function : GetTypes
5772 //purpose  : Returns types of elements it contains
5773 //=======================================================================
5774
5775 SMESH::array_of_ElementType* SMESH_Mesh_i::GetTypes()
5776 {
5777   if ( _preMeshInfo )
5778     return _preMeshInfo->GetTypes();
5779
5780   SMESH::array_of_ElementType_var types = new SMESH::array_of_ElementType;
5781
5782   types->length( 5 );
5783   int nbTypes = 0;
5784   if (_impl->NbEdges())      types[nbTypes++] = SMESH::EDGE;
5785   if (_impl->NbFaces())      types[nbTypes++] = SMESH::FACE;
5786   if (_impl->NbVolumes())    types[nbTypes++] = SMESH::VOLUME;
5787   if (_impl->Nb0DElements()) types[nbTypes++] = SMESH::ELEM0D;
5788   if (_impl->NbBalls())      types[nbTypes++] = SMESH::BALL;
5789   if (_impl->NbNodes() &&
5790       nbTypes == 0 )         types[nbTypes++] = SMESH::NODE;
5791   types->length( nbTypes );
5792
5793   return types._retn();
5794 }
5795
5796 //=======================================================================
5797 //function : GetMesh
5798 //purpose  : Returns self
5799 //=======================================================================
5800
5801 SMESH::SMESH_Mesh_ptr SMESH_Mesh_i::GetMesh()
5802 {
5803   return SMESH::SMESH_Mesh::_duplicate( _this() );
5804 }
5805
5806 //=======================================================================
5807 //function : IsMeshInfoCorrect
5808 //purpose  : * Returns false if GetMeshInfo() returns incorrect information that may
5809 //           * happen if mesh data is not yet fully loaded from the file of study.
5810 //=======================================================================
5811
5812 bool SMESH_Mesh_i::IsMeshInfoCorrect()
5813 {
5814   return _preMeshInfo ? _preMeshInfo->IsMeshInfoCorrect() : true;
5815 }
5816
5817 //=============================================================================
5818 /*!
5819  * \brief Returns number of mesh elements per each \a EntityType
5820  */
5821 //=============================================================================
5822
5823 SMESH::long_array* SMESH_Mesh_i::GetMeshInfo()
5824 {
5825   if ( _preMeshInfo )
5826     return _preMeshInfo->GetMeshInfo();
5827
5828   SMESH::long_array_var aRes = new SMESH::long_array();
5829   aRes->length(SMESH::Entity_Last);
5830   for (int i = SMESH::Entity_Node; i < SMESH::Entity_Last; i++)
5831     aRes[i] = 0;
5832   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5833   if (!aMeshDS)
5834     return aRes._retn();
5835   const SMDS_MeshInfo& aMeshInfo = aMeshDS->GetMeshInfo();
5836   for (int i = SMESH::Entity_Node; i < SMESH::Entity_Last; i++)
5837     aRes[i] = aMeshInfo.NbEntities((SMDSAbs_EntityType)i);
5838   return aRes._retn();
5839 }
5840
5841 //=============================================================================
5842 /*!
5843  * \brief Returns number of mesh elements per each \a ElementType
5844  */
5845 //=============================================================================
5846
5847 SMESH::long_array* SMESH_Mesh_i::GetNbElementsByType()
5848 {
5849   SMESH::long_array_var aRes = new SMESH::long_array();
5850   aRes->length(SMESH::NB_ELEMENT_TYPES);
5851   for (int i = 0; i < SMESH::NB_ELEMENT_TYPES; i++)
5852     aRes[ i ] = 0;
5853
5854   const SMDS_MeshInfo* meshInfo = 0;
5855   if ( _preMeshInfo )
5856     meshInfo = _preMeshInfo;
5857   else if ( SMESHDS_Mesh* meshDS = _impl->GetMeshDS() )
5858     meshInfo = & meshDS->GetMeshInfo();
5859
5860   if (meshInfo)
5861     for (int i = 0; i < SMESH::NB_ELEMENT_TYPES; i++)
5862       aRes[i] = meshInfo->NbElements((SMDSAbs_ElementType)i);
5863
5864   return aRes._retn();
5865 }
5866
5867 //=============================================================================
5868 /*
5869  * Collect statistic of mesh elements given by iterator
5870  */
5871 //=============================================================================
5872
5873 void SMESH_Mesh_i::CollectMeshInfo(const SMDS_ElemIteratorPtr theItr,
5874                                    SMESH::long_array&         theInfo)
5875 {
5876   if (!theItr) return;
5877   while (theItr->more())
5878     theInfo[ theItr->next()->GetEntityType() ]++;
5879 }
5880 //=============================================================================
5881 /*
5882  * Returns mesh unstructed grid information.
5883  */
5884 //=============================================================================
5885
5886 SALOMEDS::TMPFile* SMESH_Mesh_i::GetVtkUgStream()
5887 {
5888   SALOMEDS::TMPFile_var SeqFile;
5889   if ( SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS() ) {
5890     SMDS_UnstructuredGrid* aGrid = aMeshDS->GetGrid();
5891     if(aGrid) {
5892       vtkUnstructuredGridWriter* aWriter = vtkUnstructuredGridWriter::New();
5893       aWriter->WriteToOutputStringOn();
5894       aWriter->SetInputData(aGrid);
5895       aWriter->SetFileTypeToBinary();
5896       aWriter->Write();
5897       char* str = aWriter->GetOutputString();
5898       int size = aWriter->GetOutputStringLength();
5899
5900       //Allocate octet buffer of required size
5901       CORBA::Octet* OctetBuf = SALOMEDS::TMPFile::allocbuf(size);
5902       //Copy ostrstream content to the octet buffer
5903       memcpy(OctetBuf, str, size);
5904       //Create and return TMPFile
5905       SeqFile = new SALOMEDS::TMPFile(size, size, OctetBuf, 1);
5906       aWriter->Delete();
5907     }
5908   }
5909   return SeqFile._retn();
5910 }
5911
5912 //=============================================================================
5913 namespace /* Iterators used in SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_var obj,
5914            *                                             SMESH::ElementType        type) */
5915 {
5916   using namespace SMESH::Controls;
5917   //-----------------------------------------------------------------------------
5918   struct PredicateIterator : public SMDS_ElemIterator
5919   {
5920     SMDS_ElemIteratorPtr    _elemIter;
5921     PredicatePtr            _predicate;
5922     const SMDS_MeshElement* _elem;
5923     SMDSAbs_ElementType     _type;
5924
5925     PredicateIterator( SMDS_ElemIteratorPtr iterator,
5926                        PredicatePtr         predicate,
5927                        SMDSAbs_ElementType  type):
5928       _elemIter(iterator), _predicate(predicate), _type(type)
5929     {
5930       next();
5931     }
5932     virtual bool more()
5933     {
5934       return _elem;
5935     }
5936     virtual const SMDS_MeshElement* next()
5937     {
5938       const SMDS_MeshElement* res = _elem;
5939       _elem = 0;
5940       while ( _elemIter->more() && !_elem )
5941       {
5942         if ((_elem = _elemIter->next()) &&
5943             (( _type != SMDSAbs_All && _type != _elem->GetType() ) ||
5944              ( !_predicate->IsSatisfy( _elem->GetID() ))))
5945           _elem = 0;
5946       }
5947       return res;
5948     }
5949   };
5950
5951   //-----------------------------------------------------------------------------
5952   struct IDSourceIterator : public SMDS_ElemIterator
5953   {
5954     const CORBA::Long*        _idPtr;
5955     const CORBA::Long*        _idEndPtr;
5956     SMESH::long_array_var     _idArray;
5957     const SMDS_Mesh*          _mesh;
5958     const SMDSAbs_ElementType _type;
5959     const SMDS_MeshElement*   _elem;
5960
5961     IDSourceIterator( const SMDS_Mesh*    mesh,
5962                       const CORBA::Long*  ids,
5963                       const int           nbIds,
5964                       SMDSAbs_ElementType type):
5965       _idPtr( ids ), _idEndPtr( ids + nbIds ), _mesh( mesh ), _type( type ), _elem( 0 )
5966     {
5967       if ( _idPtr && nbIds && _mesh )
5968         next();
5969     }
5970     IDSourceIterator( const SMDS_Mesh*    mesh,
5971                       SMESH::long_array*  idArray,
5972                       SMDSAbs_ElementType type):
5973       _idPtr( 0 ), _idEndPtr( 0 ), _idArray( idArray), _mesh( mesh ), _type( type ), _elem( 0 )
5974     {
5975       if ( idArray && _mesh )
5976       {
5977         _idPtr    = &_idArray[0];
5978         _idEndPtr = _idPtr + _idArray->length();
5979         next();
5980       }
5981     }
5982     virtual bool more()
5983     {
5984       return _elem;
5985     }
5986     virtual const SMDS_MeshElement* next()
5987     {
5988       const SMDS_MeshElement* res = _elem;
5989       _elem = 0;
5990       while ( _idPtr < _idEndPtr && !_elem )
5991       {
5992         if ( _type == SMDSAbs_Node )
5993         {
5994           _elem = _mesh->FindNode( *_idPtr++ );
5995         }
5996         else if ((_elem = _mesh->FindElement( *_idPtr++ )) &&
5997                  (_elem->GetType() != _type && _type != SMDSAbs_All ))
5998         {
5999           _elem = 0;
6000         }
6001       }
6002       return res;
6003     }
6004   };
6005   //-----------------------------------------------------------------------------
6006
6007   struct NodeOfElemIterator : public SMDS_ElemIterator
6008   {
6009     TColStd_MapOfInteger    _checkedNodeIDs;
6010     SMDS_ElemIteratorPtr    _elemIter;
6011     SMDS_ElemIteratorPtr    _nodeIter;
6012     const SMDS_MeshElement* _node;
6013
6014     NodeOfElemIterator( SMDS_ElemIteratorPtr iter ): _elemIter( iter ), _node( 0 )
6015     {
6016       if ( _elemIter && _elemIter->more() )
6017       {
6018         _nodeIter = _elemIter->next()->nodesIterator();
6019         next();
6020       }
6021     }
6022     virtual bool more()
6023     {
6024       return _node;
6025     }
6026     virtual const SMDS_MeshElement* next()
6027     {
6028       const SMDS_MeshElement* res = _node;
6029       _node = 0;
6030       while ( !_node && ( _elemIter->more() || _nodeIter->more() ))
6031       {
6032         if ( _nodeIter->more() )
6033         {
6034           _node = _nodeIter->next();
6035           if ( !_checkedNodeIDs.Add( _node->GetID() ))
6036             _node = 0;
6037         }
6038         else
6039         {
6040           _nodeIter = _elemIter->next()->nodesIterator();
6041         }
6042       }
6043       return res;
6044     }
6045   };
6046 }
6047
6048 //=============================================================================
6049 /*
6050  * Return iterator on elements of given type in given object
6051  */
6052 //=============================================================================
6053
6054 SMDS_ElemIteratorPtr SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_ptr theObject,
6055                                                SMESH::ElementType        theType)
6056 {
6057   SMDS_ElemIteratorPtr  elemIt;
6058   bool                  typeOK = ( theType == SMESH::ALL );
6059   SMDSAbs_ElementType elemType = SMDSAbs_ElementType( theType );
6060
6061   SMESH::SMESH_Mesh_var meshVar = theObject->GetMesh();
6062   SMESH_Mesh_i*          mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( meshVar );
6063   if ( !mesh_i ) return elemIt;
6064   SMESHDS_Mesh*          meshDS = mesh_i->GetImpl().GetMeshDS();
6065
6066   if ( SMESH::DownCast<SMESH_Mesh_i*>( theObject ))
6067   {
6068     elemIt = meshDS->elementsIterator( elemType );
6069     typeOK = true;
6070   }
6071   else if ( SMESH_subMesh_i* submesh_i = SMESH::DownCast<SMESH_subMesh_i*>( theObject ))
6072   {
6073     SMESHDS_SubMesh* sm = ((SMESHDS_Mesh*) meshDS)->MeshElements( submesh_i->GetId() );
6074     if ( sm )
6075     {
6076       elemIt = sm->GetElements();
6077       if ( elemType != SMDSAbs_Node && elemType != SMDSAbs_All )
6078       {
6079         typeOK = ( elemIt && elemIt->more() && elemIt->next()->GetType() == elemType );
6080         elemIt = typeOK ? sm->GetElements() : SMDS_ElemIteratorPtr();
6081       }
6082     }
6083   }
6084   else if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( theObject ))
6085   {
6086     SMESHDS_GroupBase* groupDS = group_i->GetGroupDS();
6087     if ( groupDS && ( elemType == groupDS->GetType()  ||
6088                       elemType == SMDSAbs_Node ||
6089                       elemType == SMDSAbs_All ))
6090     {
6091       elemIt = groupDS->GetElements();
6092       typeOK = ( groupDS->GetType() == elemType || elemType == SMDSAbs_All );
6093     }
6094   }
6095   else if ( SMESH::Filter_i* filter_i = SMESH::DownCast<SMESH::Filter_i*>( theObject ))
6096   {
6097     if ( filter_i->GetElementType() == theType ||
6098          filter_i->GetElementType() == SMESH::ALL ||
6099          elemType == SMDSAbs_Node ||
6100          elemType == SMDSAbs_All)
6101     {
6102       SMESH::Predicate_i* pred_i = filter_i->GetPredicate_i();
6103       if ( pred_i && pred_i->GetPredicate() )
6104       {
6105         SMDSAbs_ElementType filterType = SMDSAbs_ElementType( filter_i->GetElementType() );
6106         SMDS_ElemIteratorPtr allElemIt = meshDS->elementsIterator( filterType );
6107         SMDSAbs_ElementType   iterType = elemType == SMDSAbs_Node ? filterType : elemType;
6108         elemIt = SMDS_ElemIteratorPtr
6109           ( new PredicateIterator( allElemIt, pred_i->GetPredicate(), iterType ));
6110         typeOK = ( elemType == SMDSAbs_Node ? filterType == SMDSAbs_Node : elemIt->more() );
6111       }
6112     }
6113   }
6114   else
6115   {
6116     SMESH::array_of_ElementType_var types = theObject->GetTypes();
6117     const bool                    isNodes = ( types->length() == 1 && types[0] == SMESH::NODE );
6118     if ( isNodes && elemType != SMDSAbs_Node && elemType != SMDSAbs_All )
6119       return elemIt;
6120     SMDSAbs_ElementType iterType = isNodes ? SMDSAbs_Node : elemType;
6121     if ( SMESH_MeshEditor_i::IsTemporaryIDSource( theObject ))
6122     {
6123       int nbIds;
6124       if ( CORBA::Long* ids = SMESH_MeshEditor_i::GetTemporaryIDs( theObject, nbIds ))
6125         elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids, nbIds, iterType ));
6126     }
6127     else
6128     {
6129       SMESH::long_array_var ids = theObject->GetIDs();
6130       elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids._retn(), iterType ));
6131     }
6132     typeOK = ( isNodes == ( elemType == SMDSAbs_Node )) || ( elemType == SMDSAbs_All );
6133   }
6134
6135   if ( elemIt && elemIt->more() && !typeOK )
6136   {
6137     if ( elemType == SMDSAbs_Node )
6138     {
6139       elemIt = SMDS_ElemIteratorPtr( new NodeOfElemIterator( elemIt ));
6140     }
6141     else
6142     {
6143       elemIt = SMDS_ElemIteratorPtr();
6144     }
6145   }
6146   return elemIt;
6147 }
6148
6149 //=============================================================================
6150 namespace // Finding concurrent hypotheses
6151 //=============================================================================
6152 {
6153
6154 /*!
6155  * \brief mapping of mesh dimension into shape type
6156  */
6157 TopAbs_ShapeEnum shapeTypeByDim(const int theDim)
6158 {
6159   TopAbs_ShapeEnum aType = TopAbs_SOLID;
6160   switch ( theDim ) {
6161   case 0: aType = TopAbs_VERTEX; break;
6162   case 1: aType = TopAbs_EDGE; break;
6163   case 2: aType = TopAbs_FACE; break;
6164   case 3:
6165   default:aType = TopAbs_SOLID; break;
6166   }
6167   return aType;
6168 }
6169
6170 //-----------------------------------------------------------------------------
6171 /*!
6172  * \brief Internal structure used to find concurrent submeshes
6173  *
6174  * It represents a pair < submesh, concurrent dimension >, where
6175  * 'concurrent dimension' is dimension of shape where the submesh can concurrent
6176  *  with another submesh. In other words, it is dimension of a hypothesis assigned
6177  *  to submesh.
6178  */
6179 class SMESH_DimHyp
6180 {
6181  public:
6182   //! fields
6183   int _dim;    //!< a dimension the algo can build (concurrent dimension)
6184   int _ownDim; //!< dimension of shape of _subMesh (>=_dim)
6185   TopTools_MapOfShape _shapeMap;
6186   SMESH_subMesh*      _subMesh;
6187   list<const SMESHDS_Hypothesis*> _hypotheses; //!< algo is first, then its parameters
6188
6189   //-----------------------------------------------------------------------------
6190   // Return the algorithm
6191   const SMESH_Algo* GetAlgo() const
6192   { return _hypotheses.empty() ? 0 : dynamic_cast<const SMESH_Algo*>( _hypotheses.front() ); }
6193
6194   //-----------------------------------------------------------------------------
6195   //! Constructors
6196   SMESH_DimHyp(const SMESH_subMesh* theSubMesh,
6197                const int            theDim,
6198                const TopoDS_Shape&  theShape)
6199   {
6200     _subMesh = (SMESH_subMesh*)theSubMesh;
6201     SetShape( theDim, theShape );
6202   }
6203
6204   //-----------------------------------------------------------------------------
6205   //! set shape
6206   void SetShape(const int           theDim,
6207                 const TopoDS_Shape& theShape)
6208   {
6209     _dim = theDim;
6210     _ownDim = SMESH_Gen::GetShapeDim(theShape);
6211     if (_dim >= _ownDim)
6212       _shapeMap.Add( theShape );
6213     else {
6214       TopExp_Explorer anExp( theShape, shapeTypeByDim(theDim) );
6215       for( ; anExp.More(); anExp.Next() )
6216         _shapeMap.Add( anExp.Current() );
6217     }
6218   }
6219
6220   //-----------------------------------------------------------------------------
6221   //! Check sharing of sub-shapes
6222   static bool isShareSubShapes(const TopTools_MapOfShape& theToCheck,
6223                                const TopTools_MapOfShape& theToFind,
6224                                const TopAbs_ShapeEnum     theType)
6225   {
6226     bool isShared = false;
6227     TopTools_MapIteratorOfMapOfShape anItr( theToCheck );
6228     for (; !isShared && anItr.More(); anItr.Next() )
6229     {
6230       const TopoDS_Shape aSubSh = anItr.Key();
6231       // check for case when concurrent dimensions are same
6232       isShared = theToFind.Contains( aSubSh );
6233       // check for sub-shape with concurrent dimension
6234       TopExp_Explorer anExp( aSubSh, theType );
6235       for ( ; !isShared && anExp.More(); anExp.Next() )
6236         isShared = theToFind.Contains( anExp.Current() );
6237     }
6238     return isShared;
6239   }
6240
6241   //-----------------------------------------------------------------------------
6242   //! check algorithms
6243   static bool checkAlgo(const SMESHDS_Hypothesis* theA1,
6244                         const SMESHDS_Hypothesis* theA2)
6245   {
6246     if ( !theA1 || !theA2 ||
6247          theA1->GetType() == SMESHDS_Hypothesis::PARAM_ALGO ||
6248          theA2->GetType() == SMESHDS_Hypothesis::PARAM_ALGO )
6249       return false; // one of the hypothesis is not algorithm
6250     // check algorithm names (should be equal)
6251     return strcmp( theA1->GetName(), theA2->GetName() ) == 0;
6252   }
6253
6254
6255   //-----------------------------------------------------------------------------
6256   //! Check if sub-shape hypotheses are concurrent
6257   bool IsConcurrent(const SMESH_DimHyp* theOther) const
6258   {
6259     if ( _subMesh == theOther->_subMesh )
6260       return false; // same sub-shape - should not be
6261
6262     // if ( <own dim of either of submeshes> == <concurrent dim> &&
6263     //      any of the two submeshes is not on COMPOUND shape )
6264     //  -> no concurrency
6265     bool meIsCompound    = (_subMesh->GetSubMeshDS() &&
6266                             _subMesh->GetSubMeshDS()->IsComplexSubmesh());
6267     bool otherIsCompound = (theOther->_subMesh->GetSubMeshDS() &&
6268                             theOther->_subMesh->GetSubMeshDS()->IsComplexSubmesh());
6269     if ( (_ownDim == _dim  || theOther->_ownDim == _dim ) && (!meIsCompound || !otherIsCompound))
6270       return false;
6271
6272     bool checkSubShape = isShareSubShapes( _shapeMap, theOther->_shapeMap, shapeTypeByDim(_dim));
6273     if ( !checkSubShape )
6274       return false;
6275
6276     // check algorithms to be same
6277     const SMESH_Algo* a1 = this->GetAlgo();
6278     const SMESH_Algo* a2 = theOther->GetAlgo();
6279     bool isSame = checkAlgo( a1, a2 );
6280     if ( !isSame )
6281     {
6282       if ( !a1 || !a2 )
6283         return false; // pb?
6284       return a1->GetDim() == a2->GetDim(); // different algorithms of same dim -> concurrency !
6285     }
6286
6287     // check hypothesises for concurrence (skip first as algorithm)
6288     size_t nbSame = 0;
6289     // pointers should be same, because it is referened from mesh hypothesis partition
6290     list <const SMESHDS_Hypothesis*>::const_iterator hypIt = _hypotheses.begin();
6291     list <const SMESHDS_Hypothesis*>::const_iterator otheEndIt = theOther->_hypotheses.end();
6292     for ( hypIt++ /*skip first as algo*/; hypIt != _hypotheses.end(); hypIt++ )
6293       if ( find( theOther->_hypotheses.begin(), otheEndIt, *hypIt ) != otheEndIt )
6294         nbSame++;
6295     // the submeshes are concurrent if their algorithms has different parameters
6296     return nbSame != theOther->_hypotheses.size() - 1;
6297   }
6298
6299   // Return true if algorithm of this SMESH_DimHyp is used if no
6300   // sub-mesh order is imposed by the user
6301   bool IsHigherPriorityThan( const SMESH_DimHyp* theOther ) const
6302   {
6303     // NeedDiscreteBoundary() algo has a higher priority
6304     if ( this    ->GetAlgo()->NeedDiscreteBoundary() !=
6305          theOther->GetAlgo()->NeedDiscreteBoundary() )
6306       return !this->GetAlgo()->NeedDiscreteBoundary();
6307
6308     return ( this->_subMesh->GetId() < theOther->_subMesh->GetId() );
6309   }
6310
6311 }; // end of SMESH_DimHyp
6312 //-----------------------------------------------------------------------------
6313
6314 typedef list<const SMESH_DimHyp*> TDimHypList;
6315
6316 //-----------------------------------------------------------------------------
6317
6318 void addDimHypInstance(const int                               theDim,
6319                        const TopoDS_Shape&                     theShape,
6320                        const SMESH_Algo*                       theAlgo,
6321                        const SMESH_subMesh*                    theSubMesh,
6322                        const list <const SMESHDS_Hypothesis*>& theHypList,
6323                        TDimHypList*                            theDimHypListArr )
6324 {
6325   TDimHypList& listOfdimHyp = theDimHypListArr[theDim];
6326   if ( listOfdimHyp.empty() || listOfdimHyp.back()->_subMesh != theSubMesh ) {
6327     SMESH_DimHyp* dimHyp = new SMESH_DimHyp( theSubMesh, theDim, theShape );
6328     dimHyp->_hypotheses.push_front(theAlgo);
6329     listOfdimHyp.push_back( dimHyp );
6330   }
6331
6332   SMESH_DimHyp* dimHyp = const_cast<SMESH_DimHyp*>( listOfdimHyp.back() );
6333   dimHyp->_hypotheses.insert( dimHyp->_hypotheses.end(),
6334                               theHypList.begin(), theHypList.end() );
6335 }
6336
6337 //-----------------------------------------------------------------------------
6338 void addInOrderOfPriority( const SMESH_DimHyp* theDimHyp,
6339                            TDimHypList&        theListOfConcurr)
6340 {
6341   if ( theListOfConcurr.empty() )
6342   {
6343     theListOfConcurr.push_back( theDimHyp );
6344   }
6345   else
6346   {
6347     TDimHypList::iterator hypIt = theListOfConcurr.begin();
6348     while ( hypIt != theListOfConcurr.end() &&
6349             !theDimHyp->IsHigherPriorityThan( *hypIt ))
6350       ++hypIt;
6351     theListOfConcurr.insert( hypIt, theDimHyp );
6352   }
6353 }
6354
6355 //-----------------------------------------------------------------------------
6356 void findConcurrents(const SMESH_DimHyp* theDimHyp,
6357                      const TDimHypList&  theListOfDimHyp,
6358                      TDimHypList&        theListOfConcurrHyp,
6359                      set<int>&           theSetOfConcurrId )
6360 {
6361   TDimHypList::const_reverse_iterator rIt = theListOfDimHyp.rbegin();
6362   for ( ; rIt != theListOfDimHyp.rend(); rIt++ )
6363   {
6364     const SMESH_DimHyp* curDimHyp = *rIt;
6365     if ( curDimHyp == theDimHyp )
6366       break; // meet own dimHyp pointer in same dimension
6367
6368     if ( theDimHyp->IsConcurrent( curDimHyp ) &&
6369          theSetOfConcurrId.insert( curDimHyp->_subMesh->GetId() ).second )
6370     {
6371       addInOrderOfPriority( curDimHyp, theListOfConcurrHyp );
6372     }
6373   }
6374 }
6375
6376 //-----------------------------------------------------------------------------
6377 void unionLists(TListOfInt&       theListOfId,
6378                 TListOfListOfInt& theListOfListOfId,
6379                 const int         theIndx )
6380 {
6381   TListOfListOfInt::iterator it = theListOfListOfId.begin();
6382   for ( int i = 0; it != theListOfListOfId.end(); it++, i++ ) {
6383     if ( i < theIndx )
6384       continue; //skip already treated lists
6385     // check if other list has any same submesh object
6386     TListOfInt& otherListOfId = *it;
6387     if ( find_first_of( theListOfId.begin(), theListOfId.end(),
6388                         otherListOfId.begin(), otherListOfId.end() ) == theListOfId.end() )
6389       continue;
6390
6391     // union two lists (from source into target)
6392     TListOfInt::iterator it2 = otherListOfId.begin();
6393     for ( ; it2 != otherListOfId.end(); it2++ ) {
6394       if ( find( theListOfId.begin(), theListOfId.end(), (*it2) ) == theListOfId.end() )
6395         theListOfId.push_back(*it2);
6396     }
6397     // clear source list
6398     otherListOfId.clear();
6399   }
6400 }
6401 //-----------------------------------------------------------------------------
6402
6403 //! free memory allocated for dimension-hypothesis objects
6404 void removeDimHyps( TDimHypList* theArrOfList )
6405 {
6406   for (int i = 0; i < 4; i++ ) {
6407     TDimHypList& listOfdimHyp = theArrOfList[i];
6408     TDimHypList::const_iterator it = listOfdimHyp.begin();
6409     for ( ; it != listOfdimHyp.end(); it++ )
6410       delete (*it);
6411   }
6412 }
6413
6414 //-----------------------------------------------------------------------------
6415 /*!
6416  * \brief find common submeshes with given submesh
6417  * \param theSubMeshList list of already collected submesh to check
6418  * \param theSubMesh given submesh to intersect with other
6419  * \param theCommonSubMeshes collected common submeshes
6420  */
6421 void findCommonSubMesh (list<const SMESH_subMesh*>& theSubMeshList,
6422                         const SMESH_subMesh*        theSubMesh,
6423                         set<const SMESH_subMesh*>&  theCommon )
6424 {
6425   if ( !theSubMesh )
6426     return;
6427   list<const SMESH_subMesh*>::const_iterator it = theSubMeshList.begin();
6428   for ( ; it != theSubMeshList.end(); it++ )
6429     theSubMesh->FindIntersection( *it, theCommon );
6430   theSubMeshList.push_back( theSubMesh );
6431   //theCommon.insert( theSubMesh );
6432 }
6433
6434 //-----------------------------------------------------------------------------
6435 bool isSubMeshInList ( int smID, const TListOfListOfInt& smLists )
6436 {
6437   TListOfListOfInt::const_iterator listsIt = smLists.begin();
6438   for ( ; listsIt != smLists.end(); ++listsIt )
6439   {
6440     const TListOfInt& smIDs = *listsIt;
6441     if ( std::find( smIDs.begin(), smIDs.end(), smID ) != smIDs.end() )
6442       return true;
6443   }
6444   return false;
6445 }
6446
6447 } // namespace
6448
6449 //=============================================================================
6450 /*!
6451  * \brief Return \c true if a meshing order not yet set for a concurrent sub-mesh
6452  */
6453 //=============================================================================
6454
6455 CORBA::Boolean SMESH_Mesh_i::IsUnorderedSubMesh(CORBA::Long submeshID)
6456 {
6457   TListOfListOfInt anOrder = GetImpl().GetMeshOrder(); // already defined order
6458   if ( isSubMeshInList( submeshID, anOrder ))
6459     return false;
6460
6461   TListOfListOfInt allConurrent = findConcurrentSubMeshes();
6462   return isSubMeshInList( submeshID, allConurrent );
6463 }
6464
6465 //=============================================================================
6466 /*!
6467  * \brief Return submesh objects list in meshing order
6468  */
6469 //=============================================================================
6470
6471 SMESH::submesh_array_array* SMESH_Mesh_i::GetMeshOrder()
6472 {
6473   SMESH::submesh_array_array_var aResult = new SMESH::submesh_array_array();
6474
6475   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
6476   if ( !aMeshDS )
6477     return aResult._retn();
6478
6479   TListOfListOfInt      anOrder = GetImpl().GetMeshOrder(); // already defined order
6480   TListOfListOfInt allConurrent = findConcurrentSubMeshes();
6481   anOrder.splice( anOrder.end(), allConurrent );
6482
6483   int listIndx = 0;
6484   TListOfListOfInt::iterator listIt = anOrder.begin();
6485   for(; listIt != anOrder.end(); listIt++, listIndx++ )
6486     unionLists( *listIt,  anOrder, listIndx + 1 );
6487
6488   // convert submesh ids into interface instances
6489   //  and dump command into python
6490   convertMeshOrder( anOrder, aResult, false );
6491
6492   return aResult._retn();
6493 }
6494
6495 //=============================================================================
6496 /*!
6497  * \brief Finds concurrent sub-meshes
6498  */
6499 //=============================================================================
6500
6501 TListOfListOfInt SMESH_Mesh_i::findConcurrentSubMeshes()
6502 {
6503   TListOfListOfInt anOrder;
6504   ::SMESH_Mesh& mesh = GetImpl();
6505   {
6506     // collect submeshes and detect concurrent algorithms and hypothesises
6507     TDimHypList dimHypListArr[4]; // dimHyp list for each shape dimension
6508
6509     map<int, ::SMESH_subMesh*>::iterator i_sm = _mapSubMesh.begin();
6510     for ( ; i_sm != _mapSubMesh.end(); i_sm++ ) {
6511       ::SMESH_subMesh* sm = (*i_sm).second;
6512       // shape of submesh
6513       const TopoDS_Shape& aSubMeshShape = sm->GetSubShape();
6514
6515       // list of assigned hypothesises
6516       const list <const SMESHDS_Hypothesis*>& hypList = mesh.GetHypothesisList(aSubMeshShape);
6517       // Find out dimensions where the submesh can be concurrent.
6518       // We define the dimensions by algo of each of hypotheses in hypList
6519       list <const SMESHDS_Hypothesis*>::const_iterator hypIt = hypList.begin();
6520       for( ; hypIt != hypList.end(); hypIt++ ) {
6521         SMESH_Algo* anAlgo = 0;
6522         const SMESH_Hypothesis* hyp = dynamic_cast<const SMESH_Hypothesis*>(*hypIt);
6523         if ( hyp->GetType() != SMESHDS_Hypothesis::PARAM_ALGO )
6524           // hyp it-self is algo
6525           anAlgo = (SMESH_Algo*)dynamic_cast<const SMESH_Algo*>(hyp);
6526         else {
6527           // try to find algorithm with help of sub-shapes
6528           TopExp_Explorer anExp( aSubMeshShape, shapeTypeByDim(hyp->GetDim()) );
6529           for ( ; !anAlgo && anExp.More(); anExp.Next() )
6530             anAlgo = mesh.GetGen()->GetAlgo( mesh, anExp.Current() );
6531         }
6532         if (!anAlgo)
6533           continue; // no algorithm assigned to a current submesh
6534
6535         int dim = anAlgo->GetDim(); // top concurrent dimension (see comment to SMESH_DimHyp)
6536         // the submesh can concurrent at <dim> (or lower dims if !anAlgo->NeedDiscreteBoundary())
6537
6538         // create instance of dimension-hypothesis for found concurrent dimension(s) and algorithm
6539         for ( int j = anAlgo->NeedDiscreteBoundary() ? dim : 1, jn = dim; j <= jn; j++ )
6540           addDimHypInstance( j, aSubMeshShape, anAlgo, sm, hypList, dimHypListArr );
6541       }
6542     } // end iterations on submesh
6543
6544     // iterate on created dimension-hypotheses and check for concurrents
6545     for ( int i = 0; i < 4; i++ ) {
6546       const TDimHypList& listOfDimHyp = dimHypListArr[i];
6547       // check for concurrents in own and other dimensions (step-by-step)
6548       TDimHypList::const_iterator dhIt = listOfDimHyp.begin();
6549       for ( ; dhIt != listOfDimHyp.end(); dhIt++ ) {
6550         const SMESH_DimHyp* dimHyp = *dhIt;
6551         TDimHypList listOfConcurr;
6552         set<int>    setOfConcurrIds;
6553         // looking for concurrents and collect into own list
6554         for ( int j = i; j < 4; j++ )
6555           findConcurrents( dimHyp, dimHypListArr[j], listOfConcurr, setOfConcurrIds );
6556         // check if any concurrents found
6557         if ( listOfConcurr.size() > 0 ) {
6558           // add own submesh to list of concurrent
6559           addInOrderOfPriority( dimHyp, listOfConcurr );
6560           list<int> listOfConcurrIds;
6561           TDimHypList::iterator hypIt = listOfConcurr.begin();
6562           for ( ; hypIt != listOfConcurr.end(); ++hypIt )
6563             listOfConcurrIds.push_back( (*hypIt)->_subMesh->GetId() );
6564           anOrder.push_back( listOfConcurrIds );
6565         }
6566       }
6567     }
6568
6569     removeDimHyps(dimHypListArr);
6570
6571     // now, minimize the number of concurrent groups
6572     // Here we assume that lists of submeshes can have same submesh
6573     // in case of multi-dimension algorithms, as result
6574     //  list with common submesh has to be united into one list
6575     int listIndx = 0;
6576     TListOfListOfInt::iterator listIt = anOrder.begin();
6577     for(; listIt != anOrder.end(); listIt++, listIndx++ )
6578       unionLists( *listIt,  anOrder, listIndx + 1 );
6579   }
6580
6581   return anOrder;
6582 }
6583
6584 //=============================================================================
6585 /*!
6586  * \brief Set submesh object order
6587  * \param theSubMeshArray submesh array order
6588  */
6589 //=============================================================================
6590
6591 ::CORBA::Boolean SMESH_Mesh_i::SetMeshOrder(const SMESH::submesh_array_array& theSubMeshArray)
6592 {
6593   if ( _preMeshInfo )
6594     _preMeshInfo->ForgetOrLoad();
6595
6596   bool res = false;
6597   ::SMESH_Mesh& mesh = GetImpl();
6598
6599   TPythonDump aPythonDump; // prevent dump of called methods
6600   aPythonDump << "isDone = " << SMESH::SMESH_Mesh_var(_this()) << ".SetMeshOrder( [ ";
6601
6602   TListOfListOfInt subMeshOrder;
6603   for ( int i = 0, n = theSubMeshArray.length(); i < n; i++ )
6604   {
6605     const SMESH::submesh_array& aSMArray = theSubMeshArray[i];
6606     TListOfInt subMeshIds;
6607     if ( i > 0 )
6608       aPythonDump << ", ";
6609     aPythonDump << "[ ";
6610     // Collect subMeshes which should be clear
6611     //  do it list-by-list, because modification of submesh order
6612     //  take effect between concurrent submeshes only
6613     set<const SMESH_subMesh*> subMeshToClear;
6614     list<const SMESH_subMesh*> subMeshList;
6615     for ( int j = 0, jn = aSMArray.length(); j < jn; j++ )
6616     {
6617       const SMESH::SMESH_subMesh_var subMesh = SMESH::SMESH_subMesh::_duplicate(aSMArray[j]);
6618       if ( j > 0 )
6619         aPythonDump << ", ";
6620       aPythonDump << subMesh;
6621       subMeshIds.push_back( subMesh->GetId() );
6622       // detect common parts of submeshes
6623       if ( _mapSubMesh.find(subMesh->GetId()) != _mapSubMesh.end() )
6624         findCommonSubMesh( subMeshList, _mapSubMesh[ subMesh->GetId() ], subMeshToClear );
6625     }
6626     aPythonDump << " ]";
6627     subMeshOrder.push_back( subMeshIds );
6628
6629     // clear collected sub-meshes
6630     set<const SMESH_subMesh*>::iterator clrIt = subMeshToClear.begin();
6631     for ( ; clrIt != subMeshToClear.end(); clrIt++ )
6632       if ( SMESH_subMesh* sm = (SMESH_subMesh*)*clrIt )
6633       {
6634         sm->ComputeStateEngine( SMESH_subMesh::CLEAN );
6635         if ( SMESH_Algo* algo = sm->GetAlgo() ) // #16748
6636           sm->AlgoStateEngine( SMESH_subMesh::MODIF_HYP, algo ); // to clear a cached algo
6637       }
6638   }
6639   aPythonDump << " ])";
6640
6641   mesh.SetMeshOrder( subMeshOrder );
6642   res = true;
6643
6644   SMESH::SMESH_Mesh_var me = _this();
6645   _gen_i->UpdateIcons( me );
6646
6647   return res;
6648 }
6649
6650 //=============================================================================
6651 /*!
6652  * \brief Convert submesh ids into submesh interfaces
6653  */
6654 //=============================================================================
6655
6656 void SMESH_Mesh_i::convertMeshOrder (const TListOfListOfInt&     theIdsOrder,
6657                                      SMESH::submesh_array_array& theResOrder,
6658                                      const bool                  theIsDump)
6659 {
6660   int nbSet = theIdsOrder.size();
6661   TPythonDump aPythonDump; // prevent dump of called methods
6662   if ( theIsDump )
6663     aPythonDump << "[ ";
6664   theResOrder.length(nbSet);
6665   TListOfListOfInt::const_iterator it = theIdsOrder.begin();
6666   int listIndx = 0;
6667   for( ; it != theIdsOrder.end(); it++ ) {
6668     // translate submesh identificators into submesh objects
6669     //  takeing into account real number of concurrent lists
6670     const TListOfInt& aSubOrder = (*it);
6671     if (!aSubOrder.size())
6672       continue;
6673     if ( theIsDump )
6674       aPythonDump << "[ ";
6675     // convert shape indices into interfaces
6676     SMESH::submesh_array_var aResSubSet = new SMESH::submesh_array();
6677     aResSubSet->length(aSubOrder.size());
6678     TListOfInt::const_iterator subIt = aSubOrder.begin();
6679     int j;
6680     for( j = 0; subIt != aSubOrder.end(); subIt++ ) {
6681       if ( _mapSubMeshIor.find(*subIt) == _mapSubMeshIor.end() )
6682         continue;
6683       SMESH::SMESH_subMesh_var subMesh =
6684         SMESH::SMESH_subMesh::_duplicate( _mapSubMeshIor[*subIt] );
6685       if ( theIsDump ) {
6686         if ( j > 0 )
6687           aPythonDump << ", ";
6688         aPythonDump << subMesh;
6689       }
6690       aResSubSet[ j++ ] = subMesh;
6691     }
6692     if ( theIsDump )
6693       aPythonDump << " ]";
6694     if ( j > 1 )
6695       theResOrder[ listIndx++ ] = aResSubSet;
6696   }
6697   // correct number of lists
6698   theResOrder.length( listIndx );
6699
6700   if ( theIsDump ) {
6701     // finilise python dump
6702     aPythonDump << " ]";
6703     aPythonDump << " = " << SMESH::SMESH_Mesh_var(_this()) << ".GetMeshOrder()";
6704   }
6705 }
6706
6707 namespace // utils used by SMESH_MeshPartDS
6708 {
6709   /*!
6710    * \brief Class used to access to protected data of SMDS_MeshInfo
6711    */
6712   struct TMeshInfo : public SMDS_MeshInfo
6713   {
6714     void Add(const SMDS_MeshElement* e) { SMDS_MeshInfo::addWithPoly( e ); }
6715   };
6716   /*!
6717    * \brief Element holing its ID only
6718    */
6719   struct TElemID : public SMDS_LinearEdge
6720   {
6721     TElemID(int ID) : SMDS_LinearEdge(0,0) { setID( ID ); }
6722   };
6723 }
6724
6725 //================================================================================
6726 //
6727 // Implementation of SMESH_MeshPartDS
6728 //
6729 SMESH_MeshPartDS::SMESH_MeshPartDS(SMESH::SMESH_IDSource_ptr meshPart):
6730   SMESHDS_Mesh( /*meshID=*/-1, /*isEmbeddedMode=*/true)
6731 {
6732   SMESH::SMESH_Mesh_var mesh = meshPart->GetMesh();
6733   SMESH_Mesh_i*       mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
6734
6735   mesh_i->Load();
6736   _meshDS = mesh_i->GetImpl().GetMeshDS();
6737
6738   SetPersistentId( _meshDS->GetPersistentId() );
6739
6740   if ( mesh_i == SMESH::DownCast<SMESH_Mesh_i*>( meshPart ))
6741   {
6742     // <meshPart> is the whole mesh
6743     myInfo = _meshDS->GetMeshInfo(); // copy mesh info;
6744     // copy groups
6745     set<SMESHDS_GroupBase*>& myGroupSet = const_cast<set<SMESHDS_GroupBase*>&>( GetGroups() );
6746     myGroupSet = _meshDS->GetGroups();
6747   }
6748   else
6749   {
6750     TMeshInfo tmpInfo;
6751     SMESH::long_array_var           anIDs = meshPart->GetIDs();
6752     SMESH::array_of_ElementType_var types = meshPart->GetTypes();
6753     if ( types->length() == 1 && types[0] == SMESH::NODE ) // group of nodes
6754     {
6755       for ( CORBA::ULong i=0; i < anIDs->length(); i++ )
6756         if ( const SMDS_MeshNode * n = _meshDS->FindNode( anIDs[i] ))
6757           if ( _elements[ SMDSAbs_Node ].insert( n ).second )
6758             tmpInfo.Add( n );
6759     }
6760     else
6761     {
6762       for ( CORBA::ULong i=0; i < anIDs->length(); i++ )
6763         if ( const SMDS_MeshElement * e = _meshDS->FindElement(anIDs[i]))
6764           if ( _elements[ e->GetType() ].insert( e ).second )
6765           {
6766             tmpInfo.Add( e );
6767             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
6768             while ( nIt->more() )
6769             {
6770               const SMDS_MeshNode * n = (const SMDS_MeshNode*) nIt->next();
6771               if ( _elements[ SMDSAbs_Node ].insert( n ).second )
6772                 tmpInfo.Add( n );
6773             }
6774           }
6775     }
6776     myInfo = tmpInfo;
6777
6778     ShapeToMesh( _meshDS->ShapeToMesh() );
6779
6780     _meshDS = 0; // to enforce iteration on _elements and _nodes
6781   }
6782 }
6783 // -------------------------------------------------------------------------------------
6784 SMESH_MeshPartDS::SMESH_MeshPartDS(const std::list< const SMDS_MeshElement* > & meshPart):
6785   SMESHDS_Mesh( /*meshID=*/-1, /*isEmbeddedMode=*/true), _meshDS(0)
6786 {
6787   TMeshInfo tmpInfo;
6788   list< const SMDS_MeshElement* >::const_iterator partIt = meshPart.begin();
6789   for ( ; partIt != meshPart.end(); ++partIt )
6790     if ( const SMDS_MeshElement * e = *partIt )
6791       if ( _elements[ e->GetType() ].insert( e ).second )
6792       {
6793         tmpInfo.Add( e );
6794         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
6795         while ( nIt->more() )
6796         {
6797           const SMDS_MeshNode * n = (const SMDS_MeshNode*) nIt->next();
6798           if ( _elements[ SMDSAbs_Node ].insert( n ).second )
6799             tmpInfo.Add( n );
6800         }
6801       }
6802   myInfo = tmpInfo;
6803 }
6804 // -------------------------------------------------------------------------------------
6805 const SMDS_MeshElement * SMESH_MeshPartDS::FindElement(int IDelem) const
6806 {
6807   if ( _meshDS ) return _meshDS->FindElement( IDelem );
6808
6809   TElemID elem( IDelem );
6810   for ( int iType = SMDSAbs_Edge; iType < SMDSAbs_NbElementTypes; ++iType )
6811     if ( !_elements[ iType ].empty() )
6812     {
6813       TIDSortedElemSet::const_iterator it = _elements[ iType ].find( &elem );
6814       if ( it != _elements[ iType ].end() )
6815         return *it;
6816     }
6817   return 0;
6818 }
6819 // -------------------------------------------------------------------------------------
6820 bool SMESH_MeshPartDS::HasNumerationHoles()
6821 {
6822   if ( _meshDS ) return _meshDS->HasNumerationHoles();
6823
6824   return ( MinNodeID() != 1 ||
6825            MaxNodeID() != NbNodes() ||
6826            MinElementID() != 1 ||
6827            MaxElementID() != NbElements() );
6828 }
6829 // -------------------------------------------------------------------------------------
6830 int SMESH_MeshPartDS::MaxNodeID() const
6831 {
6832   if ( _meshDS ) return _meshDS->MaxNodeID();
6833   return NbNodes() == 0 ? 0 : (*_elements[ SMDSAbs_Node ].rbegin())->GetID();
6834 }
6835 // -------------------------------------------------------------------------------------
6836 int SMESH_MeshPartDS::MinNodeID() const
6837 {
6838   if ( _meshDS ) return _meshDS->MinNodeID();
6839   return NbNodes() == 0 ? 0 : (*_elements[ SMDSAbs_Node ].begin())->GetID();
6840 }  
6841 // -------------------------------------------------------------------------------------
6842 int SMESH_MeshPartDS::MaxElementID() const
6843 {
6844   if ( _meshDS ) return _meshDS->MaxElementID();
6845   int maxID = 0;
6846   for ( int iType = SMDSAbs_Edge; iType < SMDSAbs_NbElementTypes; ++iType )
6847     if ( !_elements[ iType ].empty() )
6848       maxID = Max( maxID, (*_elements[ iType ].rbegin())->GetID() );
6849   return maxID;
6850 }
6851 // -------------------------------------------------------------------------------------
6852 int SMESH_MeshPartDS::MinElementID() const
6853 {
6854   if ( _meshDS ) return _meshDS->MinElementID();
6855   int minID = 0;
6856   for ( int iType = SMDSAbs_Edge; iType < SMDSAbs_NbElementTypes; ++iType )
6857     if ( !_elements[ iType ].empty() )
6858       minID = Min( minID, (*_elements[ iType ].begin())->GetID() );
6859   return minID;
6860 }
6861 // -------------------------------------------------------------------------------------
6862 SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementGeomIterator(SMDSAbs_GeometryType geomType) const
6863 {
6864   if ( _meshDS ) return _meshDS->elementGeomIterator( geomType );
6865
6866   typedef SMDS_SetIterator
6867     <const SMDS_MeshElement*,
6868     TIDSortedElemSet::const_iterator,
6869     SMDS::SimpleAccessor<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator>,
6870     SMDS_MeshElement::GeomFilter
6871     > TIter;
6872
6873   SMDSAbs_ElementType type = SMDS_MeshCell::ElemType( geomType );
6874
6875   return SMDS_ElemIteratorPtr( new TIter( _elements[type].begin(),
6876                                           _elements[type].end(),
6877                                           SMDS_MeshElement::GeomFilter( geomType )));
6878 }
6879 // -------------------------------------------------------------------------------------
6880 SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementEntityIterator(SMDSAbs_EntityType entity) const
6881 {
6882   if ( _meshDS ) return _meshDS->elementEntityIterator( entity );
6883
6884   typedef SMDS_SetIterator
6885     <const SMDS_MeshElement*,
6886     TIDSortedElemSet::const_iterator,
6887     SMDS::SimpleAccessor<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator>,
6888     SMDS_MeshElement::EntityFilter
6889     > TIter;
6890
6891   SMDSAbs_ElementType type = SMDS_MeshCell::ElemType( entity );
6892
6893   return SMDS_ElemIteratorPtr( new TIter( _elements[type].begin(),
6894                                           _elements[type].end(),
6895                                           SMDS_MeshElement::EntityFilter( entity )));
6896 }
6897 // -------------------------------------------------------------------------------------
6898 SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementsIterator(SMDSAbs_ElementType type) const
6899 {
6900   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator > TIter;
6901   if ( type == SMDSAbs_All && !_meshDS )
6902   {
6903     typedef vector< SMDS_ElemIteratorPtr > TIterVec;
6904     TIterVec iterVec;
6905     for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
6906       if ( !_elements[i].empty() && i != SMDSAbs_Node )
6907         iterVec.push_back
6908           ( SMDS_ElemIteratorPtr( new TIter( _elements[i].begin(), _elements[i].end() )));
6909
6910     typedef SMDS_IteratorOnIterators<const SMDS_MeshElement*, TIterVec > TIterOnIters;
6911     return SMDS_ElemIteratorPtr( new TIterOnIters( iterVec ));
6912   }
6913   return _meshDS ? _meshDS->elementsIterator(type) : SMDS_ElemIteratorPtr
6914       ( new TIter( _elements[type].begin(), _elements[type].end() ));
6915 }
6916 // -------------------------------------------------------------------------------------
6917 #define _GET_ITER_DEFINE( iterType, methName, elem, elemType)                       \
6918   iterType SMESH_MeshPartDS::methName() const                 \
6919   {                                                                                 \
6920     typedef SMDS_SetIterator<const elem*, TIDSortedElemSet::const_iterator > TIter; \
6921     return _meshDS ? _meshDS->methName() : iterType                 \
6922       ( new TIter( _elements[elemType].begin(), _elements[elemType].end() ));       \
6923   }
6924 // -------------------------------------------------------------------------------------
6925 _GET_ITER_DEFINE( SMDS_NodeIteratorPtr, nodesIterator, SMDS_MeshNode, SMDSAbs_Node )
6926 _GET_ITER_DEFINE( SMDS_EdgeIteratorPtr, edgesIterator, SMDS_MeshEdge, SMDSAbs_Edge )
6927 _GET_ITER_DEFINE( SMDS_FaceIteratorPtr, facesIterator, SMDS_MeshFace, SMDSAbs_Face )
6928 _GET_ITER_DEFINE( SMDS_VolumeIteratorPtr, volumesIterator, SMDS_MeshVolume, SMDSAbs_Volume)
6929 #undef _GET_ITER_DEFINE
6930 //
6931 // END Implementation of SMESH_MeshPartDS
6932 //
6933 //================================================================================