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