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