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