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