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