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