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