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