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