Salome HOME
Fix sub-mesh update upon shaper geometry change
[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 =
2006     geomGen->GetIGroupOperations();
2007   GEOM::ListOfLong_var ids = groupOp->GetObjects( theGeomObj );
2008
2009   // store data
2010   _geomGroupData.push_back( TGeomGroupData() );
2011   TGeomGroupData & groupData = _geomGroupData.back();
2012   // entry
2013   CORBA::String_var entry = groupSO->GetID();
2014   groupData._groupEntry = entry.in();
2015   // indices
2016   for ( CORBA::ULong i = 0; i < ids->length(); ++i )
2017     groupData._indices.insert( ids[i] );
2018   // SMESH object
2019   groupData._smeshObject = CORBA::Object::_duplicate( theSmeshObj );
2020   // shape index in SMESHDS
2021   // TopoDS_Shape shape = _gen_i->GeomObjectToShape( theGeomObj );
2022   // groupData._dsID = shape.IsNull() ? 0 : _impl->GetSubMesh( shape )->GetId();
2023 }
2024
2025 //================================================================================
2026 /*!
2027  * Remove GEOM group data relating to removed smesh object
2028  */
2029 //================================================================================
2030
2031 void SMESH_Mesh_i::removeGeomGroupData(CORBA::Object_ptr theSmeshObj)
2032 {
2033   list<TGeomGroupData>::iterator
2034     data = _geomGroupData.begin(), dataEnd = _geomGroupData.end();
2035   for ( ; data != dataEnd; ++data ) {
2036     if ( theSmeshObj->_is_equivalent( data->_smeshObject )) {
2037       _geomGroupData.erase( data );
2038       return;
2039     }
2040   }
2041 }
2042
2043 //================================================================================
2044 /*!
2045  * \brief Return new group contents if it has been changed and update group data
2046  */
2047 //================================================================================
2048 enum { ONLY_IF_CHANGED, IS_BREAK_LINK, MAIN_TRANSFORMED };
2049
2050 TopoDS_Shape SMESH_Mesh_i::newGroupShape( TGeomGroupData & groupData, int how )
2051 {
2052   TopoDS_Shape newShape;
2053
2054   if ( how == IS_BREAK_LINK )
2055   {
2056     SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( groupData._smeshObject );
2057     SALOMEDS::SObject_wrap geomRefSO, geomSO;
2058     if ( !meshSO->_is_nil() &&
2059          meshSO->FindSubObject( SMESH::Tag_RefOnShape, geomRefSO.inout() ) &&
2060          geomRefSO->ReferencedObject( geomSO.inout() ))
2061     {
2062       CORBA::Object_var  geomObj = _gen_i->SObjectToObject( geomSO );
2063       GEOM::GEOM_Object_var geom = GEOM::GEOM_Object::_narrow( geomObj );
2064       newShape = _gen_i->GeomObjectToShape( geom );
2065     }
2066   }
2067   else
2068   {
2069     // get geom group
2070     SALOMEDS::SObject_wrap groupSO = SMESH_Gen_i::getStudyServant()->FindObjectID( groupData._groupEntry.c_str() );
2071     if ( !groupSO->_is_nil() )
2072     {
2073       CORBA::Object_var groupObj = _gen_i->SObjectToObject( groupSO );
2074       if ( CORBA::is_nil( groupObj )) return newShape;
2075       GEOM::GEOM_Object_var geomGroup = GEOM::GEOM_Object::_narrow( groupObj );
2076
2077       // get indices of group items
2078       set<int> curIndices;
2079       GEOM::GEOM_Gen_var              geomGen = _gen_i->GetGeomEngine( geomGroup );
2080       GEOM::GEOM_IGroupOperations_ptr groupOp = geomGen->GetIGroupOperations();
2081       GEOM::ListOfLong_var                ids = groupOp->GetObjects( geomGroup );
2082       for ( CORBA::ULong i = 0; i < ids->length(); ++i )
2083         curIndices.insert( ids[i] );
2084
2085       if ( how == ONLY_IF_CHANGED && groupData._indices == curIndices )
2086         return newShape; // group not changed
2087
2088       // update data
2089       groupData._indices = curIndices;
2090
2091       GEOM_Client* geomClient = _gen_i->GetShapeReader();
2092       if ( !geomClient ) return newShape;
2093       CORBA::String_var groupIOR = geomGen->GetStringFromIOR( geomGroup );
2094       geomClient->RemoveShapeFromBuffer( groupIOR.in() );
2095       newShape = _gen_i->GeomObjectToShape( geomGroup );
2096     }
2097   }
2098   if ( newShape.IsNull() ) {
2099     // geom group becomes empty - return empty compound
2100     TopoDS_Compound compound;
2101     BRep_Builder().MakeCompound(compound);
2102     newShape = compound;
2103   }
2104   return newShape;
2105 }
2106
2107 namespace
2108 {
2109   //-----------------------------------------------------------------------------
2110   /*!
2111    * \brief Storage of shape and index used in CheckGeomGroupModif()
2112    */
2113   struct TIndexedShape
2114   {
2115     int          _index;
2116     TopoDS_Shape _shape;
2117     TIndexedShape( int i, const TopoDS_Shape& s ):_index(i), _shape(s) {}
2118   };
2119   //-----------------------------------------------------------------------------
2120   /*!
2121    * \brief Data to re-create a group on geometry
2122    */
2123   struct TGroupOnGeomData
2124   {
2125     int                 _oldID;
2126     TopoDS_Shape        _shape;
2127     SMDSAbs_ElementType _type;
2128     std::string         _name;
2129     Quantity_Color      _color;
2130
2131     TGroupOnGeomData( const SMESHDS_GroupOnGeom* group )
2132     {
2133       _oldID = group->GetID();
2134       _type  = group->GetType();
2135       _name  = group->GetStoreName();
2136       _color = group->GetColor();
2137     }
2138   };
2139
2140   //-----------------------------------------------------------------------------
2141   /*!
2142    * \brief Check if a filter is still valid after geometry removal
2143    */
2144   bool isValidGeomFilter( SMESH::Filter_var theFilter )
2145   {
2146     if ( theFilter->_is_nil() )
2147       return false;
2148     SMESH::Filter::Criteria_var criteria;
2149     theFilter->GetCriteria( criteria.out() );
2150
2151     for ( CORBA::ULong iCr = 0; iCr < criteria->length(); ++iCr )
2152     {
2153       const char* thresholdID = criteria[ iCr ].ThresholdID.in();
2154       std::string entry;
2155       switch ( criteria[ iCr ].Type )
2156       {
2157       case SMESH::FT_BelongToGeom:
2158       case SMESH::FT_BelongToPlane:
2159       case SMESH::FT_BelongToCylinder:
2160       case SMESH::FT_BelongToGenSurface:
2161       case SMESH::FT_LyingOnGeom:
2162         entry = thresholdID;
2163         break;
2164       case SMESH::FT_ConnectedElements:
2165         if ( thresholdID )
2166         {
2167           entry = thresholdID;
2168           break;
2169         }
2170       default:
2171         continue;
2172       }
2173       SMESH_Gen_i*           gen = SMESH_Gen_i::GetSMESHGen();
2174       SALOMEDS::SObject_wrap  so = gen->getStudyServant()->FindObjectID( entry.c_str() );
2175       if ( so->_is_nil() )
2176         return false;
2177       CORBA::Object_var      obj = so->GetObject();
2178       GEOM::GEOM_Object_var geom = GEOM::GEOM_Object::_narrow( obj );
2179       if ( gen->GeomObjectToShape( geom ).IsNull() )
2180         return false;
2181
2182     } // loop on criteria
2183
2184     return true;
2185   }
2186 }
2187
2188 //=============================================================================
2189 /*!
2190  * \brief Update data if geometry changes
2191  *
2192  * Issue 0022501
2193  */
2194 //=============================================================================
2195
2196 void SMESH_Mesh_i::CheckGeomModif( bool isBreakLink )
2197 {
2198   SMESH::SMESH_Mesh_var me = _this();
2199   GEOM::GEOM_Object_var mainGO = GetShapeToMesh();
2200
2201   TPythonDump dumpNothing; // prevent any dump
2202
2203   //bool removedFromClient = false;
2204
2205   if ( mainGO->_is_nil() ) // GEOM_Client cleared or geometry removed? (IPAL52735, PAL23636)
2206   {
2207     //removedFromClient = _impl->HasShapeToMesh();
2208
2209     // try to find geometry by study reference
2210     SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( me );
2211     SALOMEDS::SObject_wrap geomRefSO, geomSO;
2212     if ( !meshSO->_is_nil() &&
2213          meshSO->FindSubObject( SMESH::Tag_RefOnShape, geomRefSO.inout() ) &&
2214          geomRefSO->ReferencedObject( geomSO.inout() ))
2215     {
2216       CORBA::Object_var geomObj = _gen_i->SObjectToObject( geomSO );
2217       mainGO = GEOM::GEOM_Object::_narrow( geomObj );
2218     }
2219
2220     if ( mainGO->_is_nil() &&    // geometry removed ==>
2221          !geomRefSO->_is_nil() ) // remove geom dependent data: sub-meshes etc.
2222     {
2223       // convert geom dependent groups into standalone ones
2224       CheckGeomGroupModif();
2225
2226       _impl->ShapeToMesh( TopoDS_Shape() );
2227
2228       // remove sub-meshes
2229       std::map<int, SMESH::SMESH_subMesh_ptr>::iterator i_sm = _mapSubMeshIor.begin();
2230       while ( i_sm != _mapSubMeshIor.end() )
2231       {
2232         SMESH::SMESH_subMesh_ptr sm = i_sm->second;
2233         ++i_sm;
2234         RemoveSubMesh( sm );
2235       }
2236       // remove all children except groups in the study
2237       SALOMEDS::StudyBuilder_var builder = _gen_i->getStudyServant()->NewBuilder();
2238       SALOMEDS::SObject_wrap so;
2239       for ( CORBA::Long tag = SMESH::Tag_RefOnShape; tag <= SMESH::Tag_LastSubMesh; ++tag )
2240         if ( meshSO->FindSubObject( tag, so.inout() ))
2241           builder->RemoveObjectWithChildren( so );
2242
2243       _gen_i->SetPixMap( meshSO, "ICON_SMESH_TREE_MESH_IMPORTED" );
2244
2245       return;
2246     }
2247   }
2248
2249   if ( !_impl->HasShapeToMesh() ) return;
2250
2251
2252   // Update after group modification
2253
2254   if ( mainGO->GetType() == GEOM_GROUP ||    // is group or not modified
2255        mainGO->GetTick() == _mainShapeTick )
2256   {
2257     int nb = NbNodes() + NbElements();
2258     CheckGeomGroupModif();
2259     if ( nb != NbNodes() + NbElements() ) // something removed due to hypotheses change
2260       _gen_i->UpdateIcons( me );
2261     return;
2262   }
2263
2264   // Update after shape modification
2265
2266   GEOM_Client* geomClient = _gen_i->GetShapeReader();
2267   if ( !geomClient ) return;
2268   GEOM::GEOM_Gen_var geomGen = _gen_i->GetGeomEngine( mainGO );
2269   if ( geomGen->_is_nil() ) return;
2270
2271   CORBA::String_var ior = geomGen->GetStringFromIOR( mainGO );
2272   geomClient->RemoveShapeFromBuffer( ior.in() );
2273
2274   // Update data taking into account that if topology doesn't change
2275   // all sub-shapes change but IDs of sub-shapes remain (except for geom groups)
2276
2277   if ( _preMeshInfo )
2278     _preMeshInfo->ForgetAllData();
2279
2280   _impl->Clear();
2281   TopoDS_Shape newShape = _gen_i->GeomObjectToShape( mainGO );
2282   if ( newShape.IsNull() )
2283     return;
2284
2285   _mainShapeTick = mainGO->GetTick();
2286
2287   SMESHDS_Mesh * meshDS = _impl->GetMeshDS();
2288
2289   // store data of groups on geometry
2290   std::vector< TGroupOnGeomData > groupsData;
2291   const std::set<SMESHDS_GroupBase*>& groups = meshDS->GetGroups();
2292   groupsData.reserve( groups.size() );
2293   TopTools_DataMapOfShapeShape old2newShapeMap;
2294   std::set<SMESHDS_GroupBase*>::const_iterator g = groups.begin();
2295   for ( ; g != groups.end(); ++g )
2296   {
2297     if ( const SMESHDS_GroupOnGeom* group = dynamic_cast< SMESHDS_GroupOnGeom* >( *g ))
2298     {
2299       groupsData.push_back( TGroupOnGeomData( group ));
2300
2301       // get a new shape
2302       SMESH::SMESH_GroupOnGeom_var gog;
2303       std::map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_grp = _mapGroups.find( group->GetID() );
2304       if ( i_grp != _mapGroups.end() )
2305         gog = SMESH::SMESH_GroupOnGeom::_narrow( i_grp->second );
2306
2307       GEOM::GEOM_Object_var geom;
2308       if ( !gog->_is_nil() )
2309       {
2310         if ( isBreakLink )
2311         {
2312           SALOMEDS::SObject_wrap grpSO = _gen_i->ObjectToSObject( gog );
2313           SALOMEDS::SObject_wrap geomRefSO, geomSO;
2314           if ( !grpSO->_is_nil() &&
2315                grpSO->FindSubObject( SMESH::Tag_RefOnShape, geomRefSO.inout() ) &&
2316                geomRefSO->ReferencedObject( geomSO.inout() ))
2317           {
2318             CORBA::Object_var geomObj = _gen_i->SObjectToObject( geomSO );
2319             geom = GEOM::GEOM_Object::_narrow( geomObj );
2320           }
2321         }
2322         else
2323         {
2324           geom = gog->GetShape();
2325         }
2326       }
2327       if ( !geom->_is_nil() )
2328       {
2329         CORBA::String_var ior = geomGen->GetStringFromIOR( geom );
2330         geomClient->RemoveShapeFromBuffer( ior.in() );
2331         groupsData.back()._shape = _gen_i->GeomObjectToShape( geom );
2332         old2newShapeMap.Bind( group->GetShape(), groupsData.back()._shape );
2333       }
2334       else if ( old2newShapeMap.IsBound( group->GetShape() ))
2335       {
2336         groupsData.back()._shape = old2newShapeMap( group->GetShape() );
2337       }
2338     }
2339   }
2340   // store assigned hypotheses
2341   std::vector< pair< int, THypList > > ids2Hyps;
2342   const ShapeToHypothesis & hyps = meshDS->GetHypotheses();
2343   for ( ShapeToHypothesis::Iterator s2hyps( hyps ); s2hyps.More(); s2hyps.Next() )
2344   {
2345     const TopoDS_Shape& s = s2hyps.Key();
2346     const THypList&  hyps = s2hyps.ChangeValue();
2347     ids2Hyps.push_back( make_pair( meshDS->ShapeToIndex( s ), hyps ));
2348   }
2349
2350   // count shapes excluding compounds corresponding to geom groups
2351   int oldNbSubShapes = meshDS->MaxShapeIndex();
2352   for ( ; oldNbSubShapes > 0; --oldNbSubShapes )
2353   {
2354     const TopoDS_Shape& s = meshDS->IndexToShape( oldNbSubShapes );
2355     if ( s.IsNull() || s.ShapeType() != TopAbs_COMPOUND )
2356       break;
2357   }
2358
2359   // check if shape topology changes - save shape type per shape ID
2360   std::vector< TopAbs_ShapeEnum > shapeTypes( Max( oldNbSubShapes + 1, 1 ));
2361   for ( int shapeID = oldNbSubShapes; shapeID > 0; --shapeID )
2362     shapeTypes[ shapeID ] = meshDS->IndexToShape( shapeID ).ShapeType();
2363
2364   // change shape to mesh
2365   _impl->ShapeToMesh( TopoDS_Shape() );
2366   _impl->ShapeToMesh( newShape );
2367
2368   // check if shape topology changes - check new shape types
2369   bool sameTopology = ( oldNbSubShapes == meshDS->MaxShapeIndex() );
2370   for ( int shapeID = oldNbSubShapes; shapeID > 0 &&  sameTopology; --shapeID )
2371   {
2372     const TopoDS_Shape& s = meshDS->IndexToShape( shapeID );
2373     sameTopology = ( !s.IsNull() && s.ShapeType() == shapeTypes[ shapeID ]);
2374   }
2375
2376   // re-add shapes (compounds) of geom groups
2377   std::list<TGeomGroupData>::iterator data = _geomGroupData.begin();
2378   for ( ; data != _geomGroupData.end(); ++data )
2379   {
2380     TopoDS_Shape newShape = newGroupShape( *data, isBreakLink ? IS_BREAK_LINK : MAIN_TRANSFORMED );
2381     if ( !newShape.IsNull() )
2382     {
2383       if ( meshDS->ShapeToIndex( newShape ) > 0 ) // a group reduced to one sub-shape
2384       {
2385         TopoDS_Compound compound;
2386         BRep_Builder().MakeCompound( compound );
2387         BRep_Builder().Add( compound, newShape );
2388         newShape = compound;
2389       }
2390       _impl->GetSubMesh( newShape );
2391     }
2392   }
2393
2394   // re-assign hypotheses
2395   for ( size_t i = 0; i < ids2Hyps.size(); ++i )
2396   {
2397     if ( !sameTopology && ids2Hyps[i].first != 1 )
2398       continue; // assign only global hypos
2399     const TopoDS_Shape& s = meshDS->IndexToShape( ids2Hyps[i].first );
2400     const THypList&  hyps = ids2Hyps[i].second;
2401     THypList::const_iterator h = hyps.begin();
2402     for ( ; h != hyps.end(); ++h )
2403       _impl->AddHypothesis( s, (*h)->GetID() );
2404   }
2405
2406   if ( !sameTopology )
2407   {
2408     // remove invalid study sub-objects
2409     CheckGeomGroupModif();
2410   }
2411   else
2412   {
2413     // restore groups on geometry
2414     for ( size_t i = 0; i < groupsData.size(); ++i )
2415     {
2416       const TGroupOnGeomData& data = groupsData[i];
2417       if ( data._shape.IsNull() )
2418         continue;
2419
2420       std::map<int, SMESH::SMESH_GroupBase_ptr>::iterator i2g = _mapGroups.find( data._oldID );
2421       if ( i2g == _mapGroups.end() ) continue;
2422
2423       SMESH_GroupBase_i* gr_i = SMESH::DownCast<SMESH_GroupBase_i*>( i2g->second );
2424       if ( !gr_i ) continue;
2425
2426       SMESH_Group* g = _impl->AddGroup( data._type, data._name.c_str(), data._oldID, data._shape );
2427       if ( !g )
2428         _mapGroups.erase( i2g );
2429       else
2430         g->GetGroupDS()->SetColor( data._color );
2431     }
2432
2433     // update _mapSubMesh
2434     std::map<int, ::SMESH_subMesh*>::iterator i_sm = _mapSubMesh.begin();
2435     for ( ; i_sm != _mapSubMesh.end(); ++i_sm )
2436       i_sm->second = _impl->GetSubMesh( meshDS->IndexToShape( i_sm->first ));
2437   }
2438
2439   _gen_i->UpdateIcons( SMESH::SMESH_Mesh_var( _this() ));
2440 }
2441
2442 //=============================================================================
2443 /*!
2444  * \brief Update objects depending on changed geom groups
2445  *
2446  * NPAL16168: geometrical group edition from a submesh don't modify mesh computation
2447  * issue 0020210: Update of a smesh group after modification of the associated geom group
2448  */
2449 //=============================================================================
2450
2451 void SMESH_Mesh_i::CheckGeomGroupModif()
2452 {
2453   // remove sub-meshes referring a removed sub-shapes (if main shape still exists)
2454   SALOMEDS::StudyBuilder_var builder = _gen_i->getStudyServant()->NewBuilder();
2455   GEOM::GEOM_Object_var  mainGO = GetShapeToMesh();
2456   SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( SMESH::SMESH_Mesh_var( _this() ));
2457   if ( !mainGO->_is_nil() && !meshSO->_is_nil() )
2458   {
2459     SALOMEDS::SObject_wrap rootSO, geomRefSO, geomSO;
2460     for ( CORBA::Long tag = SMESH::Tag_FirstSubMesh; tag <= SMESH::Tag_LastSubMesh; ++tag )
2461       if ( meshSO->FindSubObject( tag, rootSO.inout() ))
2462       {
2463         int nbValid = 0, nbRemoved = 0;
2464         SALOMEDS::ChildIterator_wrap chItr = _gen_i->getStudyServant()->NewChildIterator( rootSO );
2465         for ( ; chItr->More(); chItr->Next() )
2466         {
2467           SALOMEDS::SObject_wrap smSO = chItr->Value(); // sub-mesh SO
2468           if ( !smSO->_is_nil() &&
2469                smSO->FindSubObject( SMESH::Tag_RefOnShape, geomRefSO.inout() ) &&
2470                geomRefSO->ReferencedObject( geomSO.inout() )) // find geometry by reference
2471           {
2472             CORBA::Object_var  geomObj = _gen_i->SObjectToObject( geomSO );
2473             GEOM::GEOM_Object_var geom = GEOM::GEOM_Object::_narrow( geomObj );
2474             if ( !geom->_non_existent() )
2475             {
2476               ++nbValid;
2477               continue; // keep the sub-mesh
2478             }
2479           }
2480           CORBA::Object_var     smObj = _gen_i->SObjectToObject( smSO );
2481           SMESH::SMESH_subMesh_var sm = SMESH::SMESH_subMesh::_narrow( smObj );
2482           if ( !sm->_is_nil() && !sm->_non_existent() )
2483           {
2484             GEOM::GEOM_Object_var smGeom = sm->GetSubShape();
2485             if ( smGeom->_is_nil() )
2486             {
2487               RemoveSubMesh( sm );
2488               ++nbRemoved;
2489             }
2490           }
2491           else
2492           {
2493             if ( _preMeshInfo )
2494               _preMeshInfo->ForgetAllData(); // unknown hypothesis modified
2495             builder->RemoveObjectWithChildren( smSO ); // sub-shape removed before loading SMESH
2496             ++nbRemoved;
2497           }
2498         }
2499         if ( /*nbRemoved > 0 &&*/ nbValid == 0 )
2500           builder->RemoveObjectWithChildren( rootSO );
2501       }
2502   }
2503
2504   // check for removed sub-shapes and convert geom dependent groups into standalone ones
2505   std::map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_gr = _mapGroups.begin();
2506   while ( i_gr != _mapGroups.end())
2507   {
2508     SMESH::SMESH_GroupBase_ptr group = i_gr->second;
2509     ++i_gr;
2510     SALOMEDS::SObject_wrap        groupSO = _gen_i->ObjectToSObject( group ), refSO;
2511     SMESH::SMESH_GroupOnGeom_var   onGeom = SMESH::SMESH_GroupOnGeom::_narrow  ( group );
2512     SMESH::SMESH_GroupOnFilter_var onFilt = SMESH::SMESH_GroupOnFilter::_narrow( group );
2513     bool isValidGeom = false;
2514     if ( !onGeom->_is_nil() )
2515     {
2516       isValidGeom = ( ! GEOM::GEOM_Object_var( onGeom->GetShape() )->_is_nil() );
2517     }
2518     else if ( !onFilt->_is_nil() )
2519     {
2520       isValidGeom = isValidGeomFilter( onFilt->GetFilter() );
2521     }
2522     else // standalone
2523     {
2524       isValidGeom = ( !groupSO->_is_nil() &&
2525                       !groupSO->FindSubObject( SMESH::Tag_RefOnShape, refSO.inout() ));
2526     }
2527     if ( !isValidGeom )
2528     {
2529       if ( !IsLoaded() || group->IsEmpty() )
2530       {
2531         RemoveGroup( group );
2532       }
2533       else if ( !onGeom->_is_nil() || !onFilt->_is_nil() )
2534       {
2535         SMESH::SMESH_Group_var ( ConvertToStandalone( group ));
2536       }
2537       else // is it possible?
2538       {
2539         builder->RemoveObjectWithChildren( refSO );
2540       }
2541     }
2542   }
2543
2544
2545   if ( !_impl->HasShapeToMesh() ) return;
2546
2547   CORBA::Long nbEntities = NbNodes() + NbElements();
2548
2549   // Check if group contents changed
2550
2551   typedef map< string, TopoDS_Shape > TEntry2Geom;
2552   TEntry2Geom newGroupContents;
2553
2554   list<TGeomGroupData>::iterator
2555     data = _geomGroupData.begin(), dataEnd = _geomGroupData.end();
2556   for ( ; data != dataEnd; ++data )
2557   {
2558     pair< TEntry2Geom::iterator, bool > it_new =
2559       newGroupContents.insert( make_pair( data->_groupEntry, TopoDS_Shape() ));
2560     bool processedGroup    = !it_new.second;
2561     TopoDS_Shape& newShape = it_new.first->second;
2562     if ( !processedGroup )
2563       newShape = newGroupShape( *data, ONLY_IF_CHANGED );
2564     if ( newShape.IsNull() )
2565       continue; // no changes
2566
2567     if ( _preMeshInfo )
2568       _preMeshInfo->ForgetOrLoad();
2569
2570     if ( processedGroup ) { // update group indices
2571       list<TGeomGroupData>::iterator data2 = data;
2572       for ( --data2; data2->_groupEntry != data->_groupEntry; --data2) {}
2573       data->_indices = data2->_indices;
2574     }
2575
2576     // Update SMESH objects according to new GEOM group contents
2577
2578     SMESH::SMESH_subMesh_var submesh = SMESH::SMESH_subMesh::_narrow( data->_smeshObject );
2579     if ( !submesh->_is_nil() ) // -------------- Sub mesh ---------------------
2580     {
2581       int oldID = submesh->GetId();
2582       if ( !_mapSubMeshIor.count( oldID ))
2583         continue;
2584       TopoDS_Shape oldShape = _mapSubMesh[oldID]->GetSubShape();
2585
2586       // update hypotheses
2587       list <const SMESHDS_Hypothesis * > hyps = _impl->GetHypothesisList(oldShape);
2588       list <const SMESHDS_Hypothesis * >::iterator hypIt;
2589       for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2590       {
2591         _impl->RemoveHypothesis( oldShape, (*hypIt)->GetID());
2592         _impl->AddHypothesis   ( newShape, (*hypIt)->GetID());
2593       }
2594       // care of submeshes
2595       SMESH_subMesh* newSubmesh = _impl->GetSubMesh( newShape );
2596       int newID = newSubmesh->GetId();
2597       if ( newID != oldID ) {
2598         _mapSubMesh   [ newID ] = newSubmesh;
2599         _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
2600         _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
2601         _mapSubMesh.   erase(oldID);
2602         _mapSubMesh_i. erase(oldID);
2603         _mapSubMeshIor.erase(oldID);
2604         _mapSubMesh_i [ newID ]->changeLocalId( newID );
2605       }
2606       continue;
2607     }
2608
2609     SMESH::SMESH_GroupOnGeom_var smeshGroup =
2610       SMESH::SMESH_GroupOnGeom::_narrow( data->_smeshObject );
2611     if ( !smeshGroup->_is_nil() ) // ------------ GROUP -----------------------
2612     {
2613       SMESH_GroupOnGeom_i* group_i = SMESH::DownCast<SMESH_GroupOnGeom_i*>( smeshGroup );
2614       if ( group_i ) {
2615         ::SMESH_Group* group = _impl->GetGroup( group_i->GetLocalID() );
2616         SMESHDS_GroupOnGeom* ds = static_cast<SMESHDS_GroupOnGeom*>( group->GetGroupDS() );
2617         ds->SetShape( newShape );
2618       }
2619       continue;
2620     }
2621
2622     SMESH::SMESH_Mesh_var mesh = SMESH::SMESH_Mesh::_narrow( data->_smeshObject );
2623     if ( !mesh->_is_nil() ) // -------------- MESH ----------------------------
2624     {
2625       // Remove groups and submeshes basing on removed sub-shapes
2626
2627       TopTools_MapOfShape newShapeMap;
2628       TopoDS_Iterator shapeIt( newShape );
2629       for ( ; shapeIt.More(); shapeIt.Next() )
2630         newShapeMap.Add( shapeIt.Value() );
2631
2632       SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
2633       for ( shapeIt.Initialize( meshDS->ShapeToMesh() ); shapeIt.More(); shapeIt.Next() )
2634       {
2635         if ( newShapeMap.Contains( shapeIt.Value() ))
2636           continue;
2637         TopTools_IndexedMapOfShape oldShapeMap;
2638         TopExp::MapShapes( shapeIt.Value(), oldShapeMap );
2639         for ( int i = 1; i <= oldShapeMap.Extent(); ++i )
2640         {
2641           const TopoDS_Shape& oldShape = oldShapeMap(i);
2642           int oldInd = meshDS->ShapeToIndex( oldShape );
2643           // -- submeshes --
2644           map<int, SMESH::SMESH_subMesh_ptr>::iterator i_smIor = _mapSubMeshIor.find( oldInd );
2645           if ( i_smIor != _mapSubMeshIor.end() ) {
2646             RemoveSubMesh( i_smIor->second ); // one submesh per shape index
2647           }
2648           // --- groups ---
2649           map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_grp = _mapGroups.begin();
2650           for ( ; i_grp != _mapGroups.end(); ++i_grp )
2651           {
2652             // check if a group bases on oldInd shape
2653             SMESHDS_GroupOnGeom* grpOnGeom = 0;
2654             if ( ::SMESH_Group* g = _impl->GetGroup( i_grp->first ))
2655               grpOnGeom = dynamic_cast<SMESHDS_GroupOnGeom*>( g->GetGroupDS() );
2656             if ( grpOnGeom && oldShape.IsSame( grpOnGeom->GetShape() ))
2657             { // remove
2658               RemoveGroup( i_grp->second ); // several groups can base on same shape
2659               i_grp = _mapGroups.begin(); // _mapGroups changed - restart iteration
2660             }
2661           }
2662         }
2663       }
2664       // Reassign hypotheses and update groups after setting the new shape to mesh
2665
2666       // collect anassigned hypotheses
2667       typedef list< pair< TIndexedShape, list<const SMESHDS_Hypothesis*> > > TShapeHypList;
2668       list <const SMESHDS_Hypothesis * >::const_iterator hypIt;
2669       TShapeHypList assignedHyps;
2670       for ( int i = 1; i <= meshDS->MaxShapeIndex(); ++i )
2671       {
2672         const TopoDS_Shape& oldShape = meshDS->IndexToShape(i);
2673         list<const SMESHDS_Hypothesis*> hyps = meshDS->GetHypothesis( oldShape );// copy
2674         if ( !hyps.empty() ) {
2675           assignedHyps.push_back( make_pair( TIndexedShape(i,oldShape), hyps ));
2676           for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2677             _impl->RemoveHypothesis( oldShape, (*hypIt)->GetID());
2678         }
2679       }
2680       // collect shapes supporting groups
2681       typedef list < pair< TIndexedShape, SMDSAbs_ElementType > > TShapeTypeList;
2682       TShapeTypeList groupData;
2683       const set<SMESHDS_GroupBase*>& groups = meshDS->GetGroups();
2684       set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2685       for ( ; grIt != groups.end(); ++grIt )
2686       {
2687         if ( SMESHDS_GroupOnGeom* gog = dynamic_cast<SMESHDS_GroupOnGeom*>( *grIt ))
2688           groupData.push_back
2689             ( make_pair( TIndexedShape( gog->GetID(),gog->GetShape()), gog->GetType()));
2690       }
2691       // set new shape to mesh -> DS of sub-meshes and geom groups is deleted
2692       _impl->Clear();
2693       _impl->ShapeToMesh( TopoDS_Shape() ); // IPAL52730
2694       _impl->ShapeToMesh( newShape );
2695
2696       // reassign hypotheses
2697       TShapeHypList::iterator indS_hyps = assignedHyps.begin();
2698       for ( ; indS_hyps != assignedHyps.end(); ++indS_hyps )
2699       {
2700         TIndexedShape&                   geom = indS_hyps->first;
2701         list<const SMESHDS_Hypothesis*>& hyps = indS_hyps->second;
2702         int oldID = geom._index;
2703         int newID = meshDS->ShapeToIndex( geom._shape );
2704         if ( oldID == 1 ) { // main shape
2705           newID = 1;
2706           geom._shape = newShape;
2707         }
2708         if ( !newID )
2709           continue;
2710         for ( hypIt = hyps.begin(); hypIt != hyps.end(); ++hypIt )
2711           _impl->AddHypothesis( geom._shape, (*hypIt)->GetID());
2712         // care of sub-meshes
2713         SMESH_subMesh* newSubmesh = _impl->GetSubMesh( geom._shape );
2714         if ( newID != oldID ) {
2715           _mapSubMesh   [ newID ] = newSubmesh;
2716           _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
2717           _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
2718           _mapSubMesh.   erase(oldID);
2719           _mapSubMesh_i. erase(oldID);
2720           _mapSubMeshIor.erase(oldID);
2721           _mapSubMesh_i [ newID ]->changeLocalId( newID );
2722         }
2723       }
2724       // recreate groups
2725       TShapeTypeList::iterator geomType = groupData.begin();
2726       for ( ; geomType != groupData.end(); ++geomType )
2727       {
2728         const TIndexedShape& geom = geomType->first;
2729         int oldID = geom._index;
2730         if ( _mapGroups.find( oldID ) == _mapGroups.end() )
2731           continue;
2732         // get group name
2733         SALOMEDS::SObject_wrap groupSO = _gen_i->ObjectToSObject( _mapGroups[oldID] );
2734         CORBA::String_var      name    = groupSO->GetName();
2735         // update
2736         if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>(_mapGroups[oldID]))
2737           if ( SMESH_Group* group = _impl->AddGroup( geomType->second, name.in(),
2738                                                      /*id=*/-1, geom._shape ))
2739             group_i->changeLocalId( group->GetID() );
2740       }
2741
2742       break; // everything has been updated
2743
2744     } // update mesh
2745   } // loop on group data
2746
2747   // Update icons
2748
2749   CORBA::Long newNbEntities = NbNodes() + NbElements();
2750   list< SALOMEDS::SObject_wrap > soToUpdateIcons;
2751   if ( newNbEntities != nbEntities )
2752   {
2753     // Add all SObjects with icons to soToUpdateIcons
2754     soToUpdateIcons.push_back( _gen_i->ObjectToSObject( _this() )); // mesh
2755
2756     for (map<int, SMESH::SMESH_subMesh_ptr>::iterator i_sm = _mapSubMeshIor.begin();
2757          i_sm != _mapSubMeshIor.end(); ++i_sm ) // submeshes
2758       soToUpdateIcons.push_back( _gen_i->ObjectToSObject( i_sm->second ));
2759
2760     for ( map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_gr = _mapGroups.begin();
2761           i_gr != _mapGroups.end(); ++i_gr ) // groups
2762       soToUpdateIcons.push_back( _gen_i->ObjectToSObject( i_gr->second ));
2763   }
2764
2765   list< SALOMEDS::SObject_wrap >::iterator so = soToUpdateIcons.begin();
2766   for ( ; so != soToUpdateIcons.end(); ++so )
2767     _gen_i->SetPixMap( *so, "ICON_SMESH_TREE_MESH_WARN" );
2768 }
2769
2770 //=============================================================================
2771 /*!
2772  * \brief Create standalone group from a group on geometry or filter
2773  */
2774 //=============================================================================
2775
2776 SMESH::SMESH_Group_ptr SMESH_Mesh_i::ConvertToStandalone( SMESH::SMESH_GroupBase_ptr theGroup )
2777   throw (SALOME::SALOME_Exception)
2778 {
2779   SMESH::SMESH_Group_var aGroup;
2780
2781   SMESH_TRY;
2782
2783   if ( _preMeshInfo )
2784     _preMeshInfo->FullLoadFromFile();
2785
2786   if ( theGroup->_is_nil() )
2787     return aGroup._retn();
2788
2789   SMESH_GroupBase_i* aGroupToRem = SMESH::DownCast<SMESH_GroupBase_i*>( theGroup );
2790   if ( !aGroupToRem )
2791     return aGroup._retn();
2792
2793   const bool isOnFilter = ( SMESH::DownCast< SMESH_GroupOnFilter_i* > ( theGroup ));
2794
2795   const int anId = aGroupToRem->GetLocalID();
2796   if ( !_impl->ConvertToStandalone( anId ) )
2797     return aGroup._retn();
2798   removeGeomGroupData( theGroup );
2799
2800   SMESH_GroupBase_i* aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
2801
2802   // remove old instance of group from own map
2803   { SMESH::SMESH_GroupBase_var var( _mapGroups[anId] ); } // decref CORBA object
2804   _mapGroups.erase( anId );
2805
2806   SALOMEDS::StudyBuilder_var builder;
2807   SALOMEDS::SObject_wrap     aGroupSO;
2808   SALOMEDS::Study_var        aStudy = SMESH_Gen_i::getStudyServant();
2809   if ( !aStudy->_is_nil() ) {
2810     builder  = aStudy->NewBuilder();
2811     aGroupSO = _gen_i->ObjectToSObject( theGroup );
2812     if ( !aGroupSO->_is_nil() )
2813     {
2814       // remove reference to geometry
2815       SALOMEDS::ChildIterator_wrap chItr = aStudy->NewChildIterator(aGroupSO);
2816       for ( ; chItr->More(); chItr->Next() )
2817       {
2818         // Remove group's child SObject
2819         SALOMEDS::SObject_wrap so = chItr->Value();
2820         builder->RemoveObject( so );
2821       }
2822       // Update Python script
2823       TPythonDump() << aGroupSO << " = " << SMESH::SMESH_Mesh_var(_this())
2824                     << ".ConvertToStandalone( " << aGroupSO << " )";
2825
2826       // change icon of Group on Filter
2827       if ( isOnFilter )
2828       {
2829         // SMESH::array_of_ElementType_var elemTypes = aGroupImpl->GetTypes();
2830         // const int isEmpty = ( elemTypes->length() == 0 );
2831         // if ( !isEmpty )
2832         {
2833           SALOMEDS::GenericAttribute_wrap anAttr =
2834             builder->FindOrCreateAttribute( aGroupSO, "AttributePixMap" );
2835           SALOMEDS::AttributePixMap_wrap pm = anAttr;
2836           pm->SetPixMap( "ICON_SMESH_TREE_GROUP" );
2837         }
2838       }
2839     }
2840   }
2841
2842   // remember new group in own map
2843   aGroup = SMESH::SMESH_Group::_narrow( aGroupImpl->_this() );
2844   _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( aGroup );
2845
2846   // register CORBA object for persistence
2847   _gen_i->RegisterObject( aGroup );
2848
2849   CORBA::String_var ior = _gen_i->GetORB()->object_to_string( aGroup );
2850   builder->SetIOR( aGroupSO, ior.in() ); //  == aGroup->Register();
2851   //aGroup->Register();
2852   aGroupToRem->UnRegister();
2853
2854   SMESH_CATCH( SMESH::throwCorbaException );
2855
2856   return aGroup._retn();
2857 }
2858
2859 //=============================================================================
2860 /*!
2861  *
2862  */
2863 //=============================================================================
2864
2865 SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::createSubMesh( GEOM::GEOM_Object_ptr theSubShapeObject )
2866 {
2867   if(MYDEBUG) MESSAGE( "createSubMesh" );
2868   TopoDS_Shape  myLocSubShape = _gen_i->GeomObjectToShape(theSubShapeObject);
2869   ::SMESH_subMesh * mySubMesh = _impl->GetSubMesh(myLocSubShape);
2870   int               subMeshId = 0;
2871
2872   SMESH_subMesh_i * subMeshServant;
2873   if ( mySubMesh )
2874   {
2875     subMeshId = mySubMesh->GetId();
2876     subMeshServant = new SMESH_subMesh_i(myPOA, _gen_i, this, subMeshId);
2877   }
2878   else // "invalid sub-mesh"
2879   {
2880     // The invalid sub-mesh is created for the case where a valid sub-shape not found
2881     // by SMESH_Gen_i::CopyMeshWithGeom(). The invalid sub-mesh has GetId() < 0.
2882     if ( _mapSubMesh.empty() )
2883       subMeshId = -1;
2884     else
2885       subMeshId = _mapSubMesh.begin()->first - 1;
2886     subMeshServant = new SMESH_Invalid_subMesh_i(myPOA, _gen_i, this, subMeshId, theSubShapeObject);
2887   }
2888
2889   SMESH::SMESH_subMesh_var subMesh = subMeshServant->_this();
2890
2891   _mapSubMesh   [subMeshId] = mySubMesh;
2892   _mapSubMesh_i [subMeshId] = subMeshServant;
2893   _mapSubMeshIor[subMeshId] = SMESH::SMESH_subMesh::_duplicate( subMesh );
2894
2895   subMeshServant->Register();
2896
2897   // register CORBA object for persistence
2898   int nextId = _gen_i->RegisterObject( subMesh );
2899   if(MYDEBUG) { MESSAGE( "Add submesh to map with id = "<< nextId); }
2900   else        { nextId = 0; } // avoid "unused variable" warning
2901
2902   // to track changes of GEOM groups
2903   if ( subMeshId > 0 )
2904     addGeomGroupData( theSubShapeObject, subMesh );
2905
2906   return subMesh._retn();
2907 }
2908
2909 //=======================================================================
2910 //function : getSubMesh
2911 //purpose  :
2912 //=======================================================================
2913
2914 SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::getSubMesh(int shapeID)
2915 {
2916   map<int, SMESH::SMESH_subMesh_ptr>::iterator it = _mapSubMeshIor.find( shapeID );
2917   if ( it == _mapSubMeshIor.end() )
2918     return SMESH::SMESH_subMesh::_nil();
2919
2920   return SMESH::SMESH_subMesh::_duplicate( (*it).second );
2921 }
2922
2923 //=============================================================================
2924 /*!
2925  *
2926  */
2927 //=============================================================================
2928
2929 bool SMESH_Mesh_i::removeSubMesh (SMESH::SMESH_subMesh_ptr theSubMesh,
2930                                   GEOM::GEOM_Object_ptr    theSubShapeObject )
2931 {
2932   bool isHypChanged = false;
2933   if ( theSubMesh->_is_nil() /*|| theSubShapeObject->_is_nil()*/ )
2934     return isHypChanged;
2935
2936   const int subMeshId = theSubMesh->GetId();
2937
2938   if ( theSubShapeObject->_is_nil() )  // not published shape (IPAL13617)
2939   {
2940     SMESH_subMesh* sm;
2941     if (( _mapSubMesh.count( subMeshId )) &&
2942         ( sm = _impl->GetSubMeshContaining( subMeshId )))
2943     {
2944       TopoDS_Shape S = sm->GetSubShape();
2945       if ( !S.IsNull() )
2946       {
2947         list<const SMESHDS_Hypothesis*> hyps = _impl->GetHypothesisList( S );
2948         isHypChanged = !hyps.empty();
2949         if ( isHypChanged && _preMeshInfo )
2950           _preMeshInfo->ForgetOrLoad();
2951         list<const SMESHDS_Hypothesis*>::const_iterator hyp = hyps.begin();
2952         for ( ; hyp != hyps.end(); ++hyp )
2953           _impl->RemoveHypothesis(S, (*hyp)->GetID());
2954       }
2955     }
2956   }
2957   else
2958   {
2959     try {
2960       SMESH::ListOfHypothesis_var aHypList = GetHypothesisList( theSubShapeObject );
2961       isHypChanged = ( aHypList->length() > 0 );
2962       for ( int i = 0, n = aHypList->length(); i < n; i++ ) {
2963         removeHypothesis( theSubShapeObject, aHypList[i] );
2964       }
2965     }
2966     catch( const SALOME::SALOME_Exception& ) {
2967       INFOS("SMESH_Mesh_i::removeSubMesh(): exception caught!");
2968     }
2969     removeGeomGroupData( theSubShapeObject );
2970   }
2971
2972   // remove a servant
2973   std::map<int, SMESH_subMesh_i*>::iterator id_smi = _mapSubMesh_i.find( subMeshId );
2974   if ( id_smi != _mapSubMesh_i.end() )
2975     id_smi->second->UnRegister();
2976
2977   // remove a CORBA object
2978   std::map<int, SMESH::SMESH_subMesh_ptr>::iterator id_smptr = _mapSubMeshIor.find( subMeshId );
2979   if ( id_smptr != _mapSubMeshIor.end() )
2980     SMESH::SMESH_subMesh_var( id_smptr->second );
2981
2982   _mapSubMesh.erase(subMeshId);
2983   _mapSubMesh_i.erase(subMeshId);
2984   _mapSubMeshIor.erase(subMeshId);
2985
2986   return isHypChanged;
2987 }
2988
2989 //=============================================================================
2990 /*!
2991  *
2992  */
2993 //=============================================================================
2994
2995 SMESH::SMESH_GroupBase_ptr SMESH_Mesh_i::createGroup (SMESH::ElementType        theElemType,
2996                                                       const char*               theName,
2997                                                       const int                 theID,
2998                                                       const TopoDS_Shape&       theShape,
2999                                                       const SMESH_PredicatePtr& thePredicate )
3000 {
3001   std::string newName;
3002   if ( !theName || !theName[0] )
3003   {
3004     std::set< std::string > presentNames;
3005     std::map<int, SMESH::SMESH_GroupBase_ptr>::const_iterator i_gr = _mapGroups.begin();
3006     for ( ; i_gr != _mapGroups.end(); ++i_gr )
3007     {
3008       CORBA::String_var name = i_gr->second->GetName();
3009       presentNames.insert( name.in() );
3010     }
3011     do {
3012       newName = "noname_Group_" + SMESH_Comment( presentNames.size() + 1 );
3013     } while ( !presentNames.insert( newName ).second );
3014     theName = newName.c_str();
3015   }
3016   SMESH::SMESH_GroupBase_var aGroup;
3017   if ( SMESH_Group* g = _impl->AddGroup( (SMDSAbs_ElementType)theElemType, theName,
3018                                          theID, theShape, thePredicate ))
3019   {
3020     int anId = g->GetID();
3021     SMESH_GroupBase_i* aGroupImpl;
3022     if ( !theShape.IsNull() )
3023       aGroupImpl = new SMESH_GroupOnGeom_i( SMESH_Gen_i::GetPOA(), this, anId );
3024     else if ( thePredicate )
3025       aGroupImpl = new SMESH_GroupOnFilter_i( SMESH_Gen_i::GetPOA(), this, anId );
3026     else
3027       aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
3028
3029     aGroup = aGroupImpl->_this();
3030     _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( aGroup );
3031     aGroupImpl->Register();
3032
3033     // register CORBA object for persistence
3034     int nextId = _gen_i->RegisterObject( aGroup );
3035     if(MYDEBUG) { MESSAGE( "Add group to map with id = "<< nextId); }
3036     else        { nextId = ( nextId > 0 ); } // avoid "unused variable" warning in release mode
3037
3038     // to track changes of GEOM groups
3039     if ( !theShape.IsNull() ) {
3040       GEOM::GEOM_Object_var geom = _gen_i->ShapeToGeomObject( theShape );
3041       addGeomGroupData( geom, aGroup );
3042     }
3043   }
3044   return aGroup._retn();
3045 }
3046
3047 //=============================================================================
3048 /*!
3049  * SMESH_Mesh_i::removeGroup
3050  *
3051  * Should be called by ~SMESH_Group_i()
3052  */
3053 //=============================================================================
3054
3055 void SMESH_Mesh_i::removeGroup( const int theId )
3056 {
3057   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::removeGroup()" );
3058   if ( _mapGroups.find( theId ) != _mapGroups.end() ) {
3059     SMESH::SMESH_GroupBase_var group = _mapGroups[theId];
3060     _mapGroups.erase( theId );
3061     removeGeomGroupData( group );
3062     if ( !_impl->RemoveGroup( theId ))
3063     {
3064       // it seems to be a call up from _impl caused by hyp modification (issue 0020918)
3065       RemoveGroup( group );
3066     }
3067     group->UnRegister();
3068   }
3069 }
3070
3071 //=============================================================================
3072 /*!
3073  *
3074  */
3075 //=============================================================================
3076
3077 SMESH::log_array * SMESH_Mesh_i::GetLog(CORBA::Boolean clearAfterGet)
3078   throw(SALOME::SALOME_Exception)
3079 {
3080   SMESH::log_array_var aLog;
3081
3082   SMESH_TRY;
3083   if ( _preMeshInfo )
3084     _preMeshInfo->FullLoadFromFile();
3085
3086   list < SMESHDS_Command * >logDS = _impl->GetLog();
3087   aLog = new SMESH::log_array;
3088   int indexLog = 0;
3089   int lg = logDS.size();
3090   SCRUTE(lg);
3091   aLog->length(lg);
3092   list < SMESHDS_Command * >::iterator its = logDS.begin();
3093   while(its != logDS.end()){
3094     SMESHDS_Command *com = *its;
3095     int comType = com->GetType();
3096     //SCRUTE(comType);
3097     int lgcom = com->GetNumber();
3098     //SCRUTE(lgcom);
3099     const list < int >&intList = com->GetIndexes();
3100     int inum = intList.size();
3101     //SCRUTE(inum);
3102     list < int >::const_iterator ii = intList.begin();
3103     const list < double >&coordList = com->GetCoords();
3104     int rnum = coordList.size();
3105     //SCRUTE(rnum);
3106     list < double >::const_iterator ir = coordList.begin();
3107     aLog[indexLog].commandType = comType;
3108     aLog[indexLog].number = lgcom;
3109     aLog[indexLog].coords.length(rnum);
3110     aLog[indexLog].indexes.length(inum);
3111     for(int i = 0; i < rnum; i++){
3112       aLog[indexLog].coords[i] = *ir;
3113       //MESSAGE(" "<<i<<" "<<ir.Value());
3114       ir++;
3115     }
3116     for(int i = 0; i < inum; i++){
3117       aLog[indexLog].indexes[i] = *ii;
3118       //MESSAGE(" "<<i<<" "<<ii.Value());
3119       ii++;
3120     }
3121     indexLog++;
3122     its++;
3123   }
3124   if(clearAfterGet)
3125     _impl->ClearLog();
3126
3127   SMESH_CATCH( SMESH::throwCorbaException );
3128
3129   return aLog._retn();
3130 }
3131
3132
3133 //=============================================================================
3134 /*!
3135  *
3136  */
3137 //=============================================================================
3138
3139 void SMESH_Mesh_i::ClearLog() throw(SALOME::SALOME_Exception)
3140 {
3141   SMESH_TRY;
3142   _impl->ClearLog();
3143   SMESH_CATCH( SMESH::throwCorbaException );
3144 }
3145
3146 //=============================================================================
3147 /*!
3148  *
3149  */
3150 //=============================================================================
3151
3152 CORBA::Long SMESH_Mesh_i::GetId()throw(SALOME::SALOME_Exception)
3153 {
3154   return _id;
3155 }
3156
3157 //=============================================================================
3158 namespace
3159 {
3160   //!< implementation of struct used to call methods of SMESH_Mesh_i from SMESH_Mesh
3161   // issue 0020918: groups removal is caused by hyp modification
3162   // issue 0021208: to forget not loaded mesh data at hyp modification
3163   struct TCallUp_i : public SMESH_Mesh::TCallUp
3164   {
3165     SMESH_Mesh_i* _mesh;
3166     TCallUp_i(SMESH_Mesh_i* mesh):_mesh(mesh) {}
3167     virtual void RemoveGroup (const int theGroupID) { _mesh->removeGroup( theGroupID ); }
3168     virtual void HypothesisModified (int theHypID)  { _mesh->onHypothesisModified( theHypID ); }
3169     virtual void Load ()                            { _mesh->Load(); }
3170   };
3171 }
3172
3173 //================================================================================
3174 /*!
3175  * \brief callback from _impl to forget not loaded mesh data (issue 0021208)
3176  */
3177 //================================================================================
3178
3179 void SMESH_Mesh_i::onHypothesisModified(int theHypID)
3180 {
3181   if ( _preMeshInfo )
3182     _preMeshInfo->ForgetOrLoad();
3183
3184   SMESH::SMESH_Mesh_var mesh = _this();
3185   _gen_i->UpdateIcons( mesh );
3186
3187   // mark a hypothesis as valid after edition
3188   SALOMEDS::SComponent_wrap smeshComp = _gen_i->PublishComponent();
3189   SALOMEDS::SObject_wrap hypRoot;
3190   if ( !smeshComp->_is_nil() && 
3191        smeshComp->FindSubObject( _gen_i->GetHypothesisRootTag(), hypRoot.inout() ))
3192   {
3193     SALOMEDS::ChildIterator_wrap anIter = _gen_i->getStudyServant()->NewChildIterator( hypRoot );
3194     for ( ; anIter->More(); anIter->Next() )
3195     {
3196       SALOMEDS::SObject_wrap    hypSO = anIter->Value();
3197       CORBA::Object_var           obj = _gen_i->SObjectToObject( hypSO );
3198       SMESH::SMESH_Hypothesis_var hyp = SMESH::SMESH_Hypothesis::_narrow( obj );
3199       if ( !hyp->_is_nil() && hyp->GetId() == theHypID )
3200         _gen_i->HighLightInvalid( hyp, false );
3201     }
3202   }
3203 }
3204
3205 //=============================================================================
3206 /*!
3207  *
3208  */
3209 //=============================================================================
3210
3211 void SMESH_Mesh_i::SetImpl(::SMESH_Mesh * impl)
3212 {
3213   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::SetImpl");
3214   _impl = impl;
3215   if ( _impl )
3216     _impl->SetCallUp( new TCallUp_i(this));
3217 }
3218
3219 //=============================================================================
3220 /*!
3221  *
3222  */
3223 //=============================================================================
3224
3225 ::SMESH_Mesh & SMESH_Mesh_i::GetImpl()
3226 {
3227   if(MYDEBUG) MESSAGE("SMESH_Mesh_i::GetImpl()");
3228   return *_impl;
3229 }
3230
3231 //=============================================================================
3232 /*!
3233  * Return mesh editor
3234  */
3235 //=============================================================================
3236
3237 SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditor()
3238   throw (SALOME::SALOME_Exception)
3239 {
3240   SMESH::SMESH_MeshEditor_var aMeshEdVar;
3241
3242   SMESH_TRY;
3243   if ( _preMeshInfo )
3244     _preMeshInfo->FullLoadFromFile();
3245
3246   // Create MeshEditor
3247   if ( !_editor )
3248     _editor = new SMESH_MeshEditor_i( this, false );
3249   aMeshEdVar = _editor->_this();
3250
3251   // Update Python script
3252   TPythonDump() << _editor << " = "
3253                 << SMESH::SMESH_Mesh_var(_this()) << ".GetMeshEditor()";
3254
3255   SMESH_CATCH( SMESH::throwCorbaException );
3256
3257   return aMeshEdVar._retn();
3258 }
3259
3260 //=============================================================================
3261 /*!
3262  * Return mesh edition previewer
3263  */
3264 //=============================================================================
3265
3266 SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditPreviewer()
3267   throw (SALOME::SALOME_Exception)
3268 {
3269   SMESH::SMESH_MeshEditor_var aMeshEdVar;
3270
3271   SMESH_TRY;
3272   if ( _preMeshInfo )
3273     _preMeshInfo->FullLoadFromFile();
3274
3275   if ( !_previewEditor )
3276     _previewEditor = new SMESH_MeshEditor_i( this, true );
3277   aMeshEdVar = _previewEditor->_this();
3278
3279   SMESH_CATCH( SMESH::throwCorbaException );
3280
3281   return aMeshEdVar._retn();
3282 }
3283
3284 //================================================================================
3285 /*!
3286  * \brief Return true if the mesh has been edited since a last total re-compute
3287  *        and those modifications may prevent successful partial re-compute
3288  */
3289 //================================================================================
3290
3291 CORBA::Boolean SMESH_Mesh_i::HasModificationsToDiscard() throw(SALOME::SALOME_Exception)
3292 {
3293   Unexpect aCatch(SALOME_SalomeException);
3294   return _impl->HasModificationsToDiscard();
3295 }
3296
3297 //================================================================================
3298 /*!
3299  * \brief Returns a random unique color
3300  */
3301 //================================================================================
3302
3303 static SALOMEDS::Color getUniqueColor( const std::list<SALOMEDS::Color>& theReservedColors )
3304 {
3305   const int MAX_ATTEMPTS = 100;
3306   int cnt = 0;
3307   double tolerance = 0.5;
3308   SALOMEDS::Color col;
3309
3310   bool ok = false;
3311   while ( !ok ) {
3312     // generate random color
3313     double red    = (double)rand() / RAND_MAX;
3314     double green  = (double)rand() / RAND_MAX;
3315     double blue   = (double)rand() / RAND_MAX;
3316     // check existence in the list of the existing colors
3317     bool matched = false;
3318     std::list<SALOMEDS::Color>::const_iterator it;
3319     for ( it = theReservedColors.begin(); it != theReservedColors.end() && !matched; ++it ) {
3320       SALOMEDS::Color color = *it;
3321       double tol = fabs( color.R - red ) + fabs( color.G - green ) + fabs( color.B  - blue  );
3322       matched = tol < tolerance;
3323     }
3324     if ( (cnt+1) % 20 == 0 ) tolerance = tolerance/2;
3325     ok = ( ++cnt == MAX_ATTEMPTS ) || !matched;
3326     col.R = red;
3327     col.G = green;
3328     col.B = blue;
3329   }
3330   return col;
3331 }
3332
3333 //=============================================================================
3334 /*!
3335  * Sets auto-color mode. If it is on, groups get unique random colors
3336  */
3337 //=============================================================================
3338
3339 void SMESH_Mesh_i::SetAutoColor(CORBA::Boolean theAutoColor) throw(SALOME::SALOME_Exception)
3340 {
3341   Unexpect aCatch(SALOME_SalomeException);
3342   _impl->SetAutoColor(theAutoColor);
3343
3344   TPythonDump pyDump; // not to dump group->SetColor() from below code
3345   pyDump << SMESH::SMESH_Mesh_var(_this()) <<".SetAutoColor( "<<theAutoColor<<" )";
3346
3347   std::list<SALOMEDS::Color> aReservedColors;
3348   map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.begin();
3349   for ( ; it != _mapGroups.end(); it++ ) {
3350     if ( CORBA::is_nil( it->second )) continue;
3351     SALOMEDS::Color aColor = getUniqueColor( aReservedColors );
3352     it->second->SetColor( aColor );
3353     aReservedColors.push_back( aColor );
3354   }
3355 }
3356
3357 //=============================================================================
3358 /*!
3359  * Returns true if auto-color mode is on
3360  */
3361 //=============================================================================
3362
3363 CORBA::Boolean SMESH_Mesh_i::GetAutoColor() throw(SALOME::SALOME_Exception)
3364 {
3365   Unexpect aCatch(SALOME_SalomeException);
3366   return _impl->GetAutoColor();
3367 }
3368
3369 //=============================================================================
3370 /*!
3371  *  Checks if there are groups with equal names
3372  */
3373 //=============================================================================
3374
3375 CORBA::Boolean SMESH_Mesh_i::HasDuplicatedGroupNamesMED()
3376 {
3377   return _impl->HasDuplicatedGroupNamesMED();
3378 }
3379
3380 //================================================================================
3381 /*!
3382  * \brief Care of a file before exporting mesh into it
3383  */
3384 //================================================================================
3385
3386 void SMESH_Mesh_i::PrepareForWriting (const char* file, bool overwrite)
3387 {
3388   SMESH_File aFile( file, false );
3389   SMESH_Comment msg;
3390   if ( aFile.exists() ) {
3391     // existing filesystem node
3392     if ( !aFile.isDirectory() ) {
3393       if ( aFile.openForWriting() ) {
3394         if ( overwrite && ! aFile.remove()) {
3395           msg << "Can't replace " << aFile.getName();
3396         }
3397       } else {
3398         msg << "Can't write into " << aFile.getName();
3399       }
3400     } else {
3401       msg << "Location " << aFile.getName() << " is not a file";
3402     }
3403   }
3404   else {
3405     // nonexisting file; check if it can be created
3406     if ( !aFile.openForWriting() ) {
3407       msg << "You cannot create the file "
3408           << aFile.getName()
3409           << ". Check the directory existence and access rights";
3410     }
3411     aFile.remove();
3412   }
3413
3414   if ( !msg.empty() )
3415   {
3416     msg << ".";
3417     THROW_SALOME_CORBA_EXCEPTION(msg.c_str(), SALOME::BAD_PARAM);
3418   }
3419 }
3420
3421 //================================================================================
3422 /*!
3423  * \brief Prepares a file for export and pass names of mesh groups from study to mesh DS
3424  *  \param file - file name
3425  *  \param overwrite - to erase the file or not
3426  *  \retval string - mesh name
3427  */
3428 //================================================================================
3429
3430 string SMESH_Mesh_i::prepareMeshNameAndGroups(const char*    file,
3431                                               CORBA::Boolean overwrite)
3432 {
3433   // Perform Export
3434   PrepareForWriting(file, overwrite);
3435   string aMeshName = "Mesh";
3436   SALOMEDS::Study_var aStudy = SMESH_Gen_i::getStudyServant();
3437   if ( !aStudy->_is_nil() ) {
3438     SALOMEDS::SObject_wrap aMeshSO = _gen_i->ObjectToSObject(  _this() );
3439     if ( !aMeshSO->_is_nil() ) {
3440       CORBA::String_var name = aMeshSO->GetName();
3441       aMeshName = name;
3442       // asv : 27.10.04 : fix of 6903: check for StudyLocked before adding attributes
3443       if ( !aStudy->GetProperties()->IsLocked() )
3444       {
3445         SALOMEDS::GenericAttribute_wrap anAttr;
3446         SALOMEDS::StudyBuilder_var aStudyBuilder = aStudy->NewBuilder();
3447         anAttr=aStudyBuilder->FindOrCreateAttribute(aMeshSO, "AttributeExternalFileDef");
3448         SALOMEDS::AttributeExternalFileDef_wrap aFileName = anAttr;
3449         ASSERT(!aFileName->_is_nil());
3450         aFileName->SetValue(file);
3451         anAttr=aStudyBuilder->FindOrCreateAttribute(aMeshSO, "AttributeFileType");
3452         SALOMEDS::AttributeFileType_wrap aFileType = anAttr;
3453         ASSERT(!aFileType->_is_nil());
3454         aFileType->SetValue("FICHIERMED");
3455       }
3456     }
3457   }
3458   // Update Python script
3459   // set name of mesh before export
3460   TPythonDump() << _gen_i << ".SetName("
3461                 << SMESH::SMESH_Mesh_var(_this()) << ", '" << aMeshName.c_str() << "')";
3462
3463   // check names of groups
3464   checkGroupNames();
3465
3466   return aMeshName;
3467 }
3468
3469 //================================================================================
3470 /*!
3471  * \brief Export to MED file
3472  */
3473 //================================================================================
3474
3475 void SMESH_Mesh_i::ExportMED(const char*        file,
3476                              CORBA::Boolean     auto_groups,
3477                              CORBA::Long        version,
3478                              CORBA::Boolean     overwrite,
3479                              CORBA::Boolean     autoDimension)
3480   throw(SALOME::SALOME_Exception)
3481 {
3482   //MESSAGE("MED minor version: "<< minor);
3483   SMESH_TRY;
3484   if ( _preMeshInfo )
3485     _preMeshInfo->FullLoadFromFile();
3486
3487   string aMeshName = prepareMeshNameAndGroups(file, overwrite);
3488   _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version, 0, autoDimension );
3489
3490   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportMED( r'"
3491                 << file << "', "
3492                 << "auto_groups=" <<auto_groups << ", "
3493                 << "minor=" << version <<  ", "
3494                 << "overwrite=" << overwrite << ", "
3495                 << "meshPart=None, "
3496                 << "autoDimension=" << autoDimension << " )";
3497
3498   SMESH_CATCH( SMESH::throwCorbaException );
3499 }
3500
3501 //================================================================================
3502 /*!
3503  * \brief Export a mesh to a SAUV file
3504  */
3505 //================================================================================
3506
3507 void SMESH_Mesh_i::ExportSAUV (const char* file,
3508                                CORBA::Boolean auto_groups)
3509   throw(SALOME::SALOME_Exception)
3510 {
3511   Unexpect aCatch(SALOME_SalomeException);
3512   if ( _preMeshInfo )
3513     _preMeshInfo->FullLoadFromFile();
3514
3515   string aMeshName = prepareMeshNameAndGroups(file, true);
3516   TPythonDump() << SMESH::SMESH_Mesh_var( _this())
3517                 << ".ExportSAUV( r'" << file << "', " << auto_groups << " )";
3518   _impl->ExportSAUV(file, aMeshName.c_str(), auto_groups);
3519 }
3520
3521
3522 //================================================================================
3523 /*!
3524  * \brief Export a mesh to a DAT file
3525  */
3526 //================================================================================
3527
3528 void SMESH_Mesh_i::ExportDAT (const char *file)
3529   throw(SALOME::SALOME_Exception)
3530 {
3531   Unexpect aCatch(SALOME_SalomeException);
3532   if ( _preMeshInfo )
3533     _preMeshInfo->FullLoadFromFile();
3534
3535   // Update Python script
3536   // check names of groups
3537   checkGroupNames();
3538   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportDAT( r'" << file << "' )";
3539
3540   // Perform Export
3541   PrepareForWriting(file);
3542   _impl->ExportDAT(file);
3543 }
3544
3545 //================================================================================
3546 /*!
3547  * \brief Export a mesh to an UNV file
3548  */
3549 //================================================================================
3550
3551 void SMESH_Mesh_i::ExportUNV (const char *file)
3552   throw(SALOME::SALOME_Exception)
3553 {
3554   Unexpect aCatch(SALOME_SalomeException);
3555   if ( _preMeshInfo )
3556     _preMeshInfo->FullLoadFromFile();
3557
3558   // Update Python script
3559   // check names of groups
3560   checkGroupNames();
3561   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportUNV( r'" << file << "' )";
3562
3563   // Perform Export
3564   PrepareForWriting(file);
3565   _impl->ExportUNV(file);
3566 }
3567
3568 //================================================================================
3569 /*!
3570  * \brief Export a mesh to an STL file
3571  */
3572 //================================================================================
3573
3574 void SMESH_Mesh_i::ExportSTL (const char *file, const bool isascii)
3575   throw(SALOME::SALOME_Exception)
3576 {
3577   Unexpect aCatch(SALOME_SalomeException);
3578   if ( _preMeshInfo )
3579     _preMeshInfo->FullLoadFromFile();
3580
3581   // Update Python script
3582   // check names of groups
3583   checkGroupNames();
3584   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
3585                 << ".ExportSTL( r'" << file << "', " << isascii << " )";
3586
3587   CORBA::String_var name;
3588   SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( _this() );
3589   if ( !so->_is_nil() )
3590     name = so->GetName();
3591
3592   // Perform Export
3593   PrepareForWriting( file );
3594   _impl->ExportSTL( file, isascii, name.in() );
3595 }
3596
3597 //================================================================================
3598 /*!
3599  * \brief Export a part of mesh to a med file
3600  */
3601 //================================================================================
3602
3603 void SMESH_Mesh_i::ExportPartToMED(SMESH::SMESH_IDSource_ptr meshPart,
3604                                    const char*               file,
3605                                    CORBA::Boolean            auto_groups,
3606                                    CORBA::Long               version,
3607                                    CORBA::Boolean            overwrite,
3608                                    CORBA::Boolean            autoDimension,
3609                                    const GEOM::ListOfFields& fields,
3610                                    const char*               geomAssocFields,
3611                                    CORBA::Double             ZTolerance)
3612   throw (SALOME::SALOME_Exception)
3613 {
3614   MESSAGE("MED version: "<< version);
3615   SMESH_TRY;
3616   if ( _preMeshInfo )
3617     _preMeshInfo->FullLoadFromFile();
3618
3619   // check fields
3620   bool have0dField = false;
3621   if ( fields.length() > 0 )
3622   {
3623     GEOM::GEOM_Object_var shapeToMesh = GetShapeToMesh();
3624     if ( shapeToMesh->_is_nil() )
3625       THROW_SALOME_CORBA_EXCEPTION( "No shape to mesh", SALOME::INTERNAL_ERROR );
3626
3627     for ( size_t i = 0; i < fields.length(); ++i )
3628     {
3629       if ( fields[i]->GetDataType() == GEOM::FDT_String )
3630         THROW_SALOME_CORBA_EXCEPTION
3631           ( "Export of string fields is not supported", SALOME::BAD_PARAM);
3632       GEOM::GEOM_Object_var fieldShape = fields[i]->GetShape();
3633       if ( fieldShape->_is_nil() )
3634         THROW_SALOME_CORBA_EXCEPTION( "Null shape under a field", SALOME::INTERNAL_ERROR );
3635       if ( !fieldShape->IsSame( shapeToMesh ) )
3636         THROW_SALOME_CORBA_EXCEPTION
3637           ( "Field defined not on shape", SALOME::BAD_PARAM);
3638       if ( fields[i]->GetDimension() == 0 )
3639         have0dField = true;
3640     }
3641     if ( geomAssocFields )
3642       for ( int i = 0; geomAssocFields[i]; ++i )
3643         switch ( geomAssocFields[i] ) {
3644         case 'v':case 'e':case 'f':case 's': break;
3645         case 'V':case 'E':case 'F':case 'S': break;
3646         default: THROW_SALOME_CORBA_EXCEPTION
3647             ( "geomAssocFields can include only [vefs] characters", SALOME::BAD_PARAM);
3648         }
3649   }
3650
3651   SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
3652
3653   // write mesh
3654
3655   string aMeshName = "Mesh";
3656   SMESHUtils::Deleter< SMESH_MeshPartDS > tmpDSDeleter(0);
3657   if ( CORBA::is_nil( meshPart ) ||
3658        SMESH::DownCast< SMESH_Mesh_i* >( meshPart ))
3659   {
3660     aMeshName = prepareMeshNameAndGroups(file, overwrite);
3661     _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version,
3662                       0, autoDimension, /*addODOnVertices=*/have0dField,
3663                       ZTolerance);
3664     meshDS = _impl->GetMeshDS();
3665   }
3666   else
3667   {
3668     if ( _preMeshInfo )
3669       _preMeshInfo->FullLoadFromFile();
3670
3671     PrepareForWriting(file, overwrite);
3672
3673     SALOMEDS::SObject_wrap SO = _gen_i->ObjectToSObject( meshPart );
3674     if ( !SO->_is_nil() ) {
3675       CORBA::String_var name = SO->GetName();
3676       aMeshName = name;
3677     }
3678
3679     SMESH_MeshPartDS* partDS = new SMESH_MeshPartDS( meshPart );
3680     _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version,
3681                       partDS, autoDimension, /*addODOnVertices=*/have0dField, ZTolerance);
3682     meshDS = tmpDSDeleter._obj = partDS;
3683   }
3684
3685   // write fields
3686
3687   if ( _impl->HasShapeToMesh() )
3688   {
3689     DriverMED_W_Field fieldWriter;
3690     fieldWriter.SetFile( file );
3691     fieldWriter.SetMeshName( aMeshName );
3692     fieldWriter.AddODOnVertices( have0dField );
3693
3694     exportMEDFields( fieldWriter, meshDS, fields, geomAssocFields );
3695   }
3696
3697   // dump
3698   GEOM::ListOfGBO_var goList = new GEOM::ListOfGBO;
3699   goList->length( fields.length() );
3700   for ( size_t i = 0; i < fields.length(); ++i )
3701   {
3702     GEOM::GEOM_BaseObject_var gbo = GEOM::GEOM_BaseObject::_narrow( fields[i] );
3703     goList[i] = gbo;
3704   }
3705   TPythonDump() << _this() << ".ExportPartToMED( "
3706                 << meshPart << ", r'"
3707                 << file << "', "
3708                 << auto_groups << ", "
3709                 << version << ", "
3710                 << overwrite << ", "
3711                 << autoDimension << ", "
3712                 << goList << ", '"
3713                 << ( geomAssocFields ? geomAssocFields : "" ) << "',"
3714                 << TVar( ZTolerance )
3715                 << " )";
3716
3717   SMESH_CATCH( SMESH::throwCorbaException );
3718 }
3719
3720 //================================================================================
3721 /*!
3722  * Write GEOM fields to MED file
3723  */
3724 //================================================================================
3725
3726 void SMESH_Mesh_i::exportMEDFields( DriverMED_W_Field&        fieldWriter,
3727                                     SMESHDS_Mesh*             meshDS,
3728                                     const GEOM::ListOfFields& fields,
3729                                     const char*               geomAssocFields)
3730 {
3731 #define METH "SMESH_Mesh_i::exportMEDFields() "
3732
3733   if (( fields.length() < 1 ) &&
3734       ( !geomAssocFields || !geomAssocFields[0] ))
3735     return;
3736
3737   std::vector< std::vector< double > > dblVals;
3738   std::vector< std::vector< int > >    intVals;
3739   std::vector< int >                   subIdsByDim[ 4 ];
3740   const double noneDblValue = 0.;
3741   const double noneIntValue = 0;
3742
3743   for ( size_t iF = 0; iF < fields.length(); ++iF )
3744   {
3745     // set field data
3746
3747     int dim = fields[ iF ]->GetDimension();
3748     SMDSAbs_ElementType elemType;
3749     TopAbs_ShapeEnum    shapeType;
3750     switch ( dim ) {
3751     case 0: elemType = SMDSAbs_0DElement; shapeType = TopAbs_VERTEX; break;
3752     case 1: elemType = SMDSAbs_Edge;      shapeType = TopAbs_EDGE;   break;
3753     case 2: elemType = SMDSAbs_Face;      shapeType = TopAbs_FACE;   break;
3754     case 3: elemType = SMDSAbs_Volume;    shapeType = TopAbs_SOLID;  break;
3755     default:
3756       continue; // skip fields on whole shape
3757     }
3758     GEOM::field_data_type dataType = fields[ iF ]->GetDataType();
3759     if ( dataType == GEOM::FDT_String )
3760       continue;
3761     GEOM::ListOfLong_var stepIDs = fields[ iF ]->GetSteps();
3762     if ( stepIDs->length() < 1 )
3763       continue;
3764     GEOM::string_array_var comps = fields[ iF ]->GetComponents();
3765     if ( comps->length() < 1 )
3766       continue;
3767     CORBA::String_var       name = fields[ iF ]->GetName();
3768
3769     if ( !fieldWriter.Set( meshDS,
3770                            name.in(),
3771                            elemType,
3772                            comps->length(),
3773                            /*isIntData=*/false ))//( dataType == GEOM::FDT_Int )))
3774       continue;
3775
3776     for ( size_t iC = 0; iC < comps->length(); ++iC )
3777       fieldWriter.SetCompName( iC, comps[ iC ].in() );
3778
3779     dblVals.resize( comps->length() );
3780     intVals.resize( comps->length() );
3781
3782     // find sub-shape IDs
3783
3784     std::vector< int >& subIds = subIdsByDim[ dim ];
3785     if ( subIds.empty() )
3786       for ( int id = 1; id <= meshDS->MaxShapeIndex(); ++id )
3787         if ( meshDS->IndexToShape( id ).ShapeType() == shapeType )
3788           subIds.push_back( id );
3789
3790     // write steps
3791
3792     SMDS_ElemIteratorPtr elemIt = fieldWriter.GetOrderedElems();
3793     if ( !elemIt )
3794       continue;
3795
3796     for ( size_t iS = 0; iS < stepIDs->length(); ++iS )
3797     {
3798       GEOM::GEOM_FieldStep_var step = fields[ iF ]->GetStep( stepIDs[ iS ]);
3799       if ( step->_is_nil() )
3800         continue;
3801
3802       CORBA::Long stamp = step->GetStamp();
3803       CORBA::Long id    = step->GetID();
3804       fieldWriter.SetDtIt( int( stamp ), int( id ));
3805
3806       // fill dblVals or intVals
3807       for ( size_t iC = 0; iC < comps->length(); ++iC )
3808         if ( dataType == GEOM::FDT_Double )
3809         {
3810           dblVals[ iC ].clear();
3811           dblVals[ iC ].resize( meshDS->MaxShapeIndex()+1, 0 );
3812         }
3813         else
3814         {
3815           intVals[ iC ].clear();
3816           intVals[ iC ].resize( meshDS->MaxShapeIndex()+1, 0 );
3817         }
3818       switch ( dataType )
3819       {
3820       case GEOM::FDT_Double:
3821       {
3822         GEOM::GEOM_DoubleFieldStep_var dblStep = GEOM::GEOM_DoubleFieldStep::_narrow( step );
3823         if ( dblStep->_is_nil() ) continue;
3824         GEOM::ListOfDouble_var vv = dblStep->GetValues();
3825         if ( vv->length() != subIds.size() * comps->length() )
3826           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
3827         for ( size_t iS = 0, iV = 0; iS < subIds.size(); ++iS )
3828           for ( size_t iC = 0; iC < comps->length(); ++iC )
3829             dblVals[ iC ][ subIds[ iS ]] = vv[ iV++ ];
3830         break;
3831       }
3832       case GEOM::FDT_Int:
3833       {
3834         GEOM::GEOM_IntFieldStep_var intStep = GEOM::GEOM_IntFieldStep::_narrow( step );
3835         if ( intStep->_is_nil() ) continue;
3836         GEOM::ListOfLong_var vv = intStep->GetValues();
3837         if ( vv->length() != subIds.size() * comps->length() )
3838           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
3839         for ( size_t iS = 0, iV = 0; iS < subIds.size(); ++iS )
3840           for ( size_t iC = 0; iC < comps->length(); ++iC )
3841             intVals[ iC ][ subIds[ iS ]] = (int) vv[ iV++ ];
3842         break;
3843       }
3844       case GEOM::FDT_Bool:
3845       {
3846         GEOM::GEOM_BoolFieldStep_var boolStep = GEOM::GEOM_BoolFieldStep::_narrow( step );
3847         if ( boolStep->_is_nil() ) continue;
3848         GEOM::short_array_var vv = boolStep->GetValues();
3849         if ( vv->length() != subIds.size() * comps->length() )
3850           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
3851         for ( size_t iS = 0, iV = 0; iS < subIds.size(); ++iS )
3852           for ( size_t iC = 0; iC < comps->length(); ++iC )
3853             intVals[ iC ][ subIds[ iS ]] = (int) vv[ iV++ ];
3854         break;
3855       }
3856       default: continue;
3857       }
3858
3859       // pass values to fieldWriter
3860       elemIt = fieldWriter.GetOrderedElems();
3861       if ( dataType == GEOM::FDT_Double )
3862         while ( elemIt->more() )
3863         {
3864           const SMDS_MeshElement* e = elemIt->next();
3865           const int shapeID = e->getshapeId();
3866           if ( shapeID < 1 || shapeID >= (int) dblVals[0].size() )
3867             for ( size_t iC = 0; iC < comps->length(); ++iC )
3868               fieldWriter.AddValue( noneDblValue );
3869           else
3870             for ( size_t iC = 0; iC < comps->length(); ++iC )
3871               fieldWriter.AddValue( dblVals[ iC ][ shapeID ]);
3872         }
3873       else
3874         while ( elemIt->more() )
3875         {
3876           const SMDS_MeshElement* e = elemIt->next();
3877           const int shapeID = e->getshapeId();
3878           if ( shapeID < 1 || shapeID >= (int) intVals[0].size() )
3879             for ( size_t iC = 0; iC < comps->length(); ++iC )
3880               fieldWriter.AddValue( (double) noneIntValue );
3881           else
3882             for ( size_t iC = 0; iC < comps->length(); ++iC )
3883               fieldWriter.AddValue( (double) intVals[ iC ][ shapeID ]);
3884         }
3885
3886       // write a step
3887       fieldWriter.Perform();
3888       SMESH_ComputeErrorPtr res = fieldWriter.GetError();
3889       if ( res && res->IsKO() )
3890       {
3891         if ( res->myComment.empty() )
3892         { THROW_SALOME_CORBA_EXCEPTION( METH "Fatal error", SALOME::INTERNAL_ERROR ); }
3893         else
3894         { THROW_SALOME_CORBA_EXCEPTION( res->myComment.c_str(), SALOME::INTERNAL_ERROR ); }
3895       }
3896
3897     } // loop on steps
3898   } // loop on fields
3899
3900   if ( !geomAssocFields || !geomAssocFields[0] )
3901     return;
3902
3903   // write geomAssocFields
3904
3905   std::vector< int > shapeDim( TopAbs_SHAPE + 1 );
3906   shapeDim[ TopAbs_COMPOUND  ] = 3;
3907   shapeDim[ TopAbs_COMPSOLID ] = 3;
3908   shapeDim[ TopAbs_SOLID     ] = 3;
3909   shapeDim[ TopAbs_SHELL     ] = 2;
3910   shapeDim[ TopAbs_FACE      ] = 2;
3911   shapeDim[ TopAbs_WIRE      ] = 1;
3912   shapeDim[ TopAbs_EDGE      ] = 1;
3913   shapeDim[ TopAbs_VERTEX    ] = 0;
3914   shapeDim[ TopAbs_SHAPE     ] = 3;
3915
3916   for ( int iF = 0; geomAssocFields[ iF ]; ++iF )
3917   {
3918     std::vector< std::string > compNames;
3919     switch ( geomAssocFields[ iF ]) {
3920     case 'v': case 'V':
3921       fieldWriter.Set( meshDS, "_vertices_", SMDSAbs_Node, /*nbComps=*/2, /*isInt=*/false );
3922       compNames.push_back( "dim" );
3923       break;
3924     case 'e': case 'E':
3925       fieldWriter.Set( meshDS, "_edges_", SMDSAbs_Edge, /*nbComps=*/1, /*isInt=*/false );
3926       break;
3927     case 'f': case 'F':
3928       fieldWriter.Set( meshDS, "_faces_", SMDSAbs_Face, /*nbComps=*/1, /*isInt=*/false );
3929       break;
3930     case 's': case 'S':
3931       fieldWriter.Set( meshDS, "_solids_", SMDSAbs_Volume, /*nbComps=*/1, /*isInt=*/false );
3932       break;
3933     default: continue;
3934     }
3935     compNames.push_back( "id" );
3936     for ( size_t iC = 0; iC < compNames.size(); ++iC )
3937       fieldWriter.SetCompName( iC, compNames[ iC ].c_str() );
3938
3939     fieldWriter.SetDtIt( -1, -1 );
3940
3941     SMDS_ElemIteratorPtr elemIt = fieldWriter.GetOrderedElems();
3942     if ( !elemIt )
3943       continue;
3944
3945     if ( compNames.size() == 2 ) // _vertices_
3946       while ( elemIt->more() )
3947       {
3948         const SMDS_MeshElement* e = elemIt->next();
3949         const int shapeID = e->getshapeId();
3950         if ( shapeID < 1 )
3951         {
3952           fieldWriter.AddValue( (double) -1 );
3953           fieldWriter.AddValue( (double) -1 );
3954         }
3955         else
3956         {
3957           const TopoDS_Shape& S = meshDS->IndexToShape( shapeID );
3958           fieldWriter.AddValue( (double) ( S.IsNull() ? -1 : shapeDim[ S.ShapeType() ]));
3959           fieldWriter.AddValue( (double) shapeID );
3960         }
3961       }
3962     else
3963       while ( elemIt->more() )
3964       {
3965         const SMDS_MeshElement* e = elemIt->next();
3966         const int shapeID = e->getshapeId();
3967         if ( shapeID < 1 )
3968           fieldWriter.AddValue( (double) -1 );
3969         else
3970           fieldWriter.AddValue( (double) shapeID );
3971       }
3972
3973     // write a step
3974     fieldWriter.Perform();
3975     SMESH_ComputeErrorPtr res = fieldWriter.GetError();
3976     if ( res && res->IsKO() )
3977     {
3978       if ( res->myComment.empty() )
3979       { THROW_SALOME_CORBA_EXCEPTION( METH "Fatal error", SALOME::INTERNAL_ERROR ); }
3980       else
3981       { THROW_SALOME_CORBA_EXCEPTION( res->myComment.c_str(), SALOME::INTERNAL_ERROR ); }
3982     }
3983
3984   } // loop on geomAssocFields
3985
3986 #undef METH
3987 }
3988
3989 //================================================================================
3990 /*!
3991  * \brief Export a part of mesh to a DAT file
3992  */
3993 //================================================================================
3994
3995 void SMESH_Mesh_i::ExportPartToDAT(::SMESH::SMESH_IDSource_ptr meshPart,
3996                                    const char*                 file)
3997   throw (SALOME::SALOME_Exception)
3998 {
3999   Unexpect aCatch(SALOME_SalomeException);
4000   if ( _preMeshInfo )
4001     _preMeshInfo->FullLoadFromFile();
4002
4003   PrepareForWriting(file);
4004
4005   SMESH_MeshPartDS partDS( meshPart );
4006   _impl->ExportDAT(file,&partDS);
4007
4008   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
4009                 << ".ExportPartToDAT( " << meshPart << ", r'" << file << "' )";
4010 }
4011 //================================================================================
4012 /*!
4013  * \brief Export a part of mesh to an UNV file
4014  */
4015 //================================================================================
4016
4017 void SMESH_Mesh_i::ExportPartToUNV(::SMESH::SMESH_IDSource_ptr meshPart,
4018                                    const char*                 file)
4019   throw (SALOME::SALOME_Exception)
4020 {
4021   Unexpect aCatch(SALOME_SalomeException);
4022   if ( _preMeshInfo )
4023     _preMeshInfo->FullLoadFromFile();
4024
4025   PrepareForWriting(file);
4026
4027   SMESH_MeshPartDS partDS( meshPart );
4028   _impl->ExportUNV(file, &partDS);
4029
4030   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
4031                 << ".ExportPartToUNV( " << meshPart<< ", r'" << file << "' )";
4032 }
4033 //================================================================================
4034 /*!
4035  * \brief Export a part of mesh to an STL file
4036  */
4037 //================================================================================
4038
4039 void SMESH_Mesh_i::ExportPartToSTL(::SMESH::SMESH_IDSource_ptr meshPart,
4040                                    const char*                 file,
4041                                    ::CORBA::Boolean            isascii)
4042   throw (SALOME::SALOME_Exception)
4043 {
4044   Unexpect aCatch(SALOME_SalomeException);
4045   if ( _preMeshInfo )
4046     _preMeshInfo->FullLoadFromFile();
4047
4048   PrepareForWriting(file);
4049
4050   CORBA::String_var name;
4051   SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( meshPart );
4052   if ( !so->_is_nil() )
4053     name = so->GetName();
4054
4055   SMESH_MeshPartDS partDS( meshPart );
4056   _impl->ExportSTL( file, isascii, name.in(), &partDS );
4057
4058   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportPartToSTL( "
4059                 << meshPart<< ", r'" << file << "', " << isascii << ")";
4060 }
4061
4062 //================================================================================
4063 /*!
4064  * \brief Export a part of mesh to an STL file
4065  */
4066 //================================================================================
4067
4068 void SMESH_Mesh_i::ExportCGNS(::SMESH::SMESH_IDSource_ptr meshPart,
4069                               const char*                 file,
4070                               CORBA::Boolean              overwrite,
4071                               CORBA::Boolean              groupElemsByType)
4072   throw (SALOME::SALOME_Exception)
4073 {
4074 #ifdef WITH_CGNS
4075   Unexpect aCatch(SALOME_SalomeException);
4076   if ( _preMeshInfo )
4077     _preMeshInfo->FullLoadFromFile();
4078
4079   PrepareForWriting(file,overwrite);
4080
4081   std::string meshName("");
4082   SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( meshPart );
4083   if ( !so->_is_nil() )
4084   {
4085     CORBA::String_var name = so->GetName();
4086     meshName = name.in();
4087   }
4088   SMESH_TRY;
4089
4090   SMESH_MeshPartDS partDS( meshPart );
4091   _impl->ExportCGNS(file, &partDS, meshName.c_str(), groupElemsByType );
4092
4093   SMESH_CATCH( SMESH::throwCorbaException );
4094
4095   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportCGNS( "
4096                 << meshPart<< ", r'" << file << "', " << overwrite << ")";
4097 #else
4098   THROW_SALOME_CORBA_EXCEPTION("CGNS library is unavailable", SALOME::INTERNAL_ERROR);
4099 #endif
4100 }
4101
4102 //================================================================================
4103 /*!
4104  * \brief Export a part of mesh to a GMF file
4105  */
4106 //================================================================================
4107
4108 void SMESH_Mesh_i::ExportGMF(::SMESH::SMESH_IDSource_ptr meshPart,
4109                              const char*                 file,
4110                              bool                        withRequiredGroups)
4111   throw (SALOME::SALOME_Exception)
4112 {
4113   Unexpect aCatch(SALOME_SalomeException);
4114   if ( _preMeshInfo )
4115     _preMeshInfo->FullLoadFromFile();
4116
4117   PrepareForWriting(file,/*overwrite=*/true);
4118
4119   SMESH_MeshPartDS partDS( meshPart );
4120   _impl->ExportGMF(file, &partDS, withRequiredGroups);
4121
4122   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportGMF( "
4123                 << meshPart<< ", r'"
4124                 << file << "', "
4125                 << withRequiredGroups << ")";
4126 }
4127
4128 //=============================================================================
4129 /*!
4130  * Return computation progress [0.,1]
4131  */
4132 //=============================================================================
4133
4134 CORBA::Double SMESH_Mesh_i::GetComputeProgress()
4135 {
4136   SMESH_TRY;
4137
4138   return _impl->GetComputeProgress();
4139
4140   SMESH_CATCH( SMESH::doNothing );
4141   return 0.;
4142 }
4143
4144 CORBA::Long SMESH_Mesh_i::NbNodes()throw(SALOME::SALOME_Exception)
4145 {
4146   Unexpect aCatch(SALOME_SalomeException);
4147   if ( _preMeshInfo )
4148     return _preMeshInfo->NbNodes();
4149
4150   return _impl->NbNodes();
4151 }
4152
4153 CORBA::Long SMESH_Mesh_i::NbElements()throw (SALOME::SALOME_Exception)
4154 {
4155   Unexpect aCatch(SALOME_SalomeException);
4156   if ( _preMeshInfo )
4157     return _preMeshInfo->NbElements();
4158
4159   return Nb0DElements() + NbEdges() + NbFaces() + NbVolumes() + NbBalls();
4160 }
4161
4162 CORBA::Long SMESH_Mesh_i::Nb0DElements()throw (SALOME::SALOME_Exception)
4163 {
4164   Unexpect aCatch(SALOME_SalomeException);
4165   if ( _preMeshInfo )
4166     return _preMeshInfo->Nb0DElements();
4167
4168   return _impl->Nb0DElements();
4169 }
4170
4171 CORBA::Long SMESH_Mesh_i::NbBalls() throw (SALOME::SALOME_Exception)
4172 {
4173   Unexpect aCatch(SALOME_SalomeException);
4174   if ( _preMeshInfo )
4175     return _preMeshInfo->NbBalls();
4176
4177   return _impl->NbBalls();
4178 }
4179
4180 CORBA::Long SMESH_Mesh_i::NbEdges()throw(SALOME::SALOME_Exception)
4181 {
4182   Unexpect aCatch(SALOME_SalomeException);
4183   if ( _preMeshInfo )
4184     return _preMeshInfo->NbEdges();
4185
4186   return _impl->NbEdges();
4187 }
4188
4189 CORBA::Long SMESH_Mesh_i::NbEdgesOfOrder(SMESH::ElementOrder order)
4190   throw(SALOME::SALOME_Exception)
4191 {
4192   Unexpect aCatch(SALOME_SalomeException);
4193   if ( _preMeshInfo )
4194     return _preMeshInfo->NbEdges( (SMDSAbs_ElementOrder) order );
4195
4196   return _impl->NbEdges( (SMDSAbs_ElementOrder) order);
4197 }
4198
4199 //=============================================================================
4200
4201 CORBA::Long SMESH_Mesh_i::NbFaces()throw(SALOME::SALOME_Exception)
4202 {
4203   Unexpect aCatch(SALOME_SalomeException);
4204   if ( _preMeshInfo )
4205     return _preMeshInfo->NbFaces();
4206
4207   return _impl->NbFaces();
4208 }
4209
4210 CORBA::Long SMESH_Mesh_i::NbTriangles()throw(SALOME::SALOME_Exception)
4211 {
4212   Unexpect aCatch(SALOME_SalomeException);
4213   if ( _preMeshInfo )
4214     return _preMeshInfo->NbTriangles();
4215
4216   return _impl->NbTriangles();
4217 }
4218
4219 CORBA::Long SMESH_Mesh_i::NbBiQuadTriangles()throw(SALOME::SALOME_Exception)
4220 {
4221   Unexpect aCatch(SALOME_SalomeException);
4222   if ( _preMeshInfo )
4223     return _preMeshInfo->NbBiQuadTriangles();
4224
4225   return _impl->NbBiQuadTriangles();
4226 }
4227
4228 CORBA::Long SMESH_Mesh_i::NbQuadrangles()throw(SALOME::SALOME_Exception)
4229 {
4230   Unexpect aCatch(SALOME_SalomeException);
4231   if ( _preMeshInfo )
4232     return _preMeshInfo->NbQuadrangles();
4233
4234   return _impl->NbQuadrangles();
4235 }
4236
4237 CORBA::Long SMESH_Mesh_i::NbBiQuadQuadrangles()throw(SALOME::SALOME_Exception)
4238 {
4239   Unexpect aCatch(SALOME_SalomeException);
4240   if ( _preMeshInfo )
4241     return _preMeshInfo->NbBiQuadQuadrangles();
4242
4243   return _impl->NbBiQuadQuadrangles();
4244 }
4245
4246 CORBA::Long SMESH_Mesh_i::NbPolygons() throw(SALOME::SALOME_Exception)
4247 {
4248   Unexpect aCatch(SALOME_SalomeException);
4249   if ( _preMeshInfo )
4250     return _preMeshInfo->NbPolygons();
4251
4252   return _impl->NbPolygons();
4253 }
4254
4255 CORBA::Long SMESH_Mesh_i::NbPolygonsOfOrder(SMESH::ElementOrder order) throw(SALOME::SALOME_Exception)
4256 {
4257   Unexpect aCatch(SALOME_SalomeException);
4258   if ( _preMeshInfo )
4259     return _preMeshInfo->NbPolygons((SMDSAbs_ElementOrder) order);
4260
4261   return _impl->NbPolygons((SMDSAbs_ElementOrder)order);
4262 }
4263
4264 CORBA::Long SMESH_Mesh_i::NbFacesOfOrder(SMESH::ElementOrder order)
4265   throw(SALOME::SALOME_Exception)
4266 {
4267   Unexpect aCatch(SALOME_SalomeException);
4268   if ( _preMeshInfo )
4269     return _preMeshInfo->NbFaces( (SMDSAbs_ElementOrder) order );
4270
4271   return _impl->NbFaces( (SMDSAbs_ElementOrder) order);
4272 }
4273
4274 CORBA::Long SMESH_Mesh_i::NbTrianglesOfOrder(SMESH::ElementOrder order)
4275   throw(SALOME::SALOME_Exception)
4276 {
4277   Unexpect aCatch(SALOME_SalomeException);
4278   if ( _preMeshInfo )
4279     return _preMeshInfo->NbTriangles( (SMDSAbs_ElementOrder) order );
4280
4281   return _impl->NbTriangles( (SMDSAbs_ElementOrder) order);
4282 }
4283
4284 CORBA::Long SMESH_Mesh_i::NbQuadranglesOfOrder(SMESH::ElementOrder order)
4285   throw(SALOME::SALOME_Exception)
4286 {
4287   Unexpect aCatch(SALOME_SalomeException);
4288   if ( _preMeshInfo )
4289     return _preMeshInfo->NbQuadrangles( (SMDSAbs_ElementOrder) order );
4290
4291   return _impl->NbQuadrangles( (SMDSAbs_ElementOrder) order);
4292 }
4293
4294 //=============================================================================
4295
4296 CORBA::Long SMESH_Mesh_i::NbVolumes()throw(SALOME::SALOME_Exception)
4297 {
4298   Unexpect aCatch(SALOME_SalomeException);
4299   if ( _preMeshInfo )
4300     return _preMeshInfo->NbVolumes();
4301
4302   return _impl->NbVolumes();
4303 }
4304
4305 CORBA::Long SMESH_Mesh_i::NbTetras()throw(SALOME::SALOME_Exception)
4306 {
4307   Unexpect aCatch(SALOME_SalomeException);
4308   if ( _preMeshInfo )
4309     return _preMeshInfo->NbTetras();
4310
4311   return _impl->NbTetras();
4312 }
4313
4314 CORBA::Long SMESH_Mesh_i::NbHexas()throw(SALOME::SALOME_Exception)
4315 {
4316   Unexpect aCatch(SALOME_SalomeException);
4317   if ( _preMeshInfo )
4318     return _preMeshInfo->NbHexas();
4319
4320   return _impl->NbHexas();
4321 }
4322
4323 CORBA::Long SMESH_Mesh_i::NbTriQuadraticHexas()throw(SALOME::SALOME_Exception)
4324 {
4325   Unexpect aCatch(SALOME_SalomeException);
4326   if ( _preMeshInfo )
4327     return _preMeshInfo->NbTriQuadHexas();
4328
4329   return _impl->NbTriQuadraticHexas();
4330 }
4331
4332 CORBA::Long SMESH_Mesh_i::NbPyramids()throw(SALOME::SALOME_Exception)
4333 {
4334   Unexpect aCatch(SALOME_SalomeException);
4335   if ( _preMeshInfo )
4336     return _preMeshInfo->NbPyramids();
4337
4338   return _impl->NbPyramids();
4339 }
4340
4341 CORBA::Long SMESH_Mesh_i::NbPrisms()throw(SALOME::SALOME_Exception)
4342 {
4343   Unexpect aCatch(SALOME_SalomeException);
4344   if ( _preMeshInfo )
4345     return _preMeshInfo->NbPrisms();
4346
4347   return _impl->NbPrisms();
4348 }
4349
4350 CORBA::Long SMESH_Mesh_i::NbHexagonalPrisms()throw(SALOME::SALOME_Exception)
4351 {
4352   Unexpect aCatch(SALOME_SalomeException);
4353   if ( _preMeshInfo )
4354     return _preMeshInfo->NbHexPrisms();
4355
4356   return _impl->NbHexagonalPrisms();
4357 }
4358
4359 CORBA::Long SMESH_Mesh_i::NbPolyhedrons()throw(SALOME::SALOME_Exception)
4360 {
4361   Unexpect aCatch(SALOME_SalomeException);
4362   if ( _preMeshInfo )
4363     return _preMeshInfo->NbPolyhedrons();
4364
4365   return _impl->NbPolyhedrons();
4366 }
4367
4368 CORBA::Long SMESH_Mesh_i::NbVolumesOfOrder(SMESH::ElementOrder order)
4369   throw(SALOME::SALOME_Exception)
4370 {
4371   Unexpect aCatch(SALOME_SalomeException);
4372   if ( _preMeshInfo )
4373     return _preMeshInfo->NbVolumes( (SMDSAbs_ElementOrder) order );
4374
4375   return _impl->NbVolumes( (SMDSAbs_ElementOrder) order);
4376 }
4377
4378 CORBA::Long SMESH_Mesh_i::NbTetrasOfOrder(SMESH::ElementOrder order)
4379   throw(SALOME::SALOME_Exception)
4380 {
4381   Unexpect aCatch(SALOME_SalomeException);
4382   if ( _preMeshInfo )
4383     return _preMeshInfo->NbTetras( (SMDSAbs_ElementOrder) order);
4384
4385   return _impl->NbTetras( (SMDSAbs_ElementOrder) order);
4386 }
4387
4388 CORBA::Long SMESH_Mesh_i::NbHexasOfOrder(SMESH::ElementOrder order)
4389   throw(SALOME::SALOME_Exception)
4390 {
4391   Unexpect aCatch(SALOME_SalomeException);
4392   if ( _preMeshInfo )
4393     return _preMeshInfo->NbHexas( (SMDSAbs_ElementOrder) order);
4394
4395   return _impl->NbHexas( (SMDSAbs_ElementOrder) order);
4396 }
4397
4398 CORBA::Long SMESH_Mesh_i::NbPyramidsOfOrder(SMESH::ElementOrder order)
4399   throw(SALOME::SALOME_Exception)
4400 {
4401   Unexpect aCatch(SALOME_SalomeException);
4402   if ( _preMeshInfo )
4403     return _preMeshInfo->NbPyramids( (SMDSAbs_ElementOrder) order);
4404
4405   return _impl->NbPyramids( (SMDSAbs_ElementOrder) order);
4406 }
4407
4408 CORBA::Long SMESH_Mesh_i::NbPrismsOfOrder(SMESH::ElementOrder order)
4409   throw(SALOME::SALOME_Exception)
4410 {
4411   Unexpect aCatch(SALOME_SalomeException);
4412   if ( _preMeshInfo )
4413     return _preMeshInfo->NbPrisms( (SMDSAbs_ElementOrder) order);
4414
4415   return _impl->NbPrisms( (SMDSAbs_ElementOrder) order);
4416 }
4417
4418 //=============================================================================
4419 /*!
4420  * Returns nb of published sub-meshes
4421  */
4422 //=============================================================================
4423
4424 CORBA::Long SMESH_Mesh_i::NbSubMesh()throw(SALOME::SALOME_Exception)
4425 {
4426   Unexpect aCatch(SALOME_SalomeException);
4427   return _mapSubMesh_i.size();
4428 }
4429
4430 //=============================================================================
4431 /*!
4432  * Dumps mesh into a string
4433  */
4434 //=============================================================================
4435
4436 char* SMESH_Mesh_i::Dump()
4437 {
4438   ostringstream os;
4439   _impl->Dump( os );
4440   return CORBA::string_dup( os.str().c_str() );
4441 }
4442
4443 //=============================================================================
4444 /*!
4445  * Method of SMESH_IDSource interface
4446  */
4447 //=============================================================================
4448
4449 SMESH::long_array* SMESH_Mesh_i::GetIDs()
4450 {
4451   return GetElementsId();
4452 }
4453
4454 //=============================================================================
4455 /*!
4456  * Returns ids of all elements
4457  */
4458 //=============================================================================
4459
4460 SMESH::long_array* SMESH_Mesh_i::GetElementsId()
4461   throw (SALOME::SALOME_Exception)
4462 {
4463   Unexpect aCatch(SALOME_SalomeException);
4464   if ( _preMeshInfo )
4465     _preMeshInfo->FullLoadFromFile();
4466
4467   SMESH::long_array_var aResult = new SMESH::long_array();
4468   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
4469
4470   if ( aSMESHDS_Mesh == NULL )
4471     return aResult._retn();
4472
4473   long nbElements = NbElements();
4474   aResult->length( nbElements );
4475   SMDS_ElemIteratorPtr anIt = aSMESHDS_Mesh->elementsIterator();
4476   for ( int i = 0, n = nbElements; i < n && anIt->more(); i++ )
4477     aResult[i] = anIt->next()->GetID();
4478
4479   return aResult._retn();
4480 }
4481
4482
4483 //=============================================================================
4484 /*!
4485  * Returns ids of all elements of given type
4486  */
4487 //=============================================================================
4488
4489 SMESH::long_array* SMESH_Mesh_i::GetElementsByType( SMESH::ElementType theElemType )
4490     throw (SALOME::SALOME_Exception)
4491 {
4492   Unexpect aCatch(SALOME_SalomeException);
4493   if ( _preMeshInfo )
4494     _preMeshInfo->FullLoadFromFile();
4495
4496   SMESH::long_array_var aResult = new SMESH::long_array();
4497   SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
4498
4499   if ( aSMESHDS_Mesh == NULL )
4500     return aResult._retn();
4501
4502   long nbElements = NbElements();
4503
4504   // No sense in returning ids of elements along with ids of nodes:
4505   // when theElemType == SMESH::ALL, return node ids only if
4506   // there are no elements
4507   if ( theElemType == SMESH::NODE || (theElemType == SMESH::ALL && nbElements == 0) )
4508     return GetNodesId();
4509
4510   aResult->length( nbElements );
4511
4512   int i = 0;
4513
4514   SMDS_ElemIteratorPtr anIt = aSMESHDS_Mesh->elementsIterator( (SMDSAbs_ElementType)theElemType );
4515   while ( i < nbElements && anIt->more() )
4516     aResult[i++] = anIt->next()->GetID();
4517
4518   aResult->length( i );
4519
4520   return aResult._retn();
4521 }
4522
4523 //=============================================================================
4524 /*!
4525  * Returns ids of all nodes
4526  */
4527 //=============================================================================
4528
4529 SMESH::long_array* SMESH_Mesh_i::GetNodesId()
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* aMeshDS = _impl->GetMeshDS();
4538
4539   if ( aMeshDS == NULL )
4540     return aResult._retn();
4541
4542   long nbNodes = NbNodes();
4543   aResult->length( nbNodes );
4544   SMDS_NodeIteratorPtr anIt = aMeshDS->nodesIterator();
4545   for ( int i = 0, n = nbNodes; i < n && anIt->more(); i++ )
4546     aResult[i] = anIt->next()->GetID();
4547
4548   return aResult._retn();
4549 }
4550
4551 //=============================================================================
4552 /*!
4553  *
4554  */
4555 //=============================================================================
4556
4557 SMESH::ElementType SMESH_Mesh_i::GetElementType( const CORBA::Long id, const bool iselem )
4558   throw (SALOME::SALOME_Exception)
4559 {
4560   SMESH::ElementType type = SMESH::ALL;
4561   SMESH_TRY;
4562
4563   if ( _preMeshInfo )
4564     _preMeshInfo->FullLoadFromFile();
4565
4566   type = ( SMESH::ElementType ) _impl->GetElementType( id, iselem );
4567
4568   SMESH_CATCH( SMESH::throwCorbaException );
4569
4570   return type;
4571 }
4572
4573 //=============================================================================
4574 /*!
4575  *
4576  */
4577 //=============================================================================
4578
4579 SMESH::EntityType SMESH_Mesh_i::GetElementGeomType( const CORBA::Long id )
4580   throw (SALOME::SALOME_Exception)
4581 {
4582   if ( _preMeshInfo )
4583     _preMeshInfo->FullLoadFromFile();
4584
4585   const SMDS_MeshElement* e = _impl->GetMeshDS()->FindElement(id);
4586   if ( !e )
4587     THROW_SALOME_CORBA_EXCEPTION( "invalid element id", SALOME::BAD_PARAM );
4588
4589   return ( SMESH::EntityType ) e->GetEntityType();
4590 }
4591
4592 //=============================================================================
4593 /*!
4594  *
4595  */
4596 //=============================================================================
4597
4598 SMESH::GeometryType SMESH_Mesh_i::GetElementShape( const CORBA::Long id )
4599   throw (SALOME::SALOME_Exception)
4600 {
4601   if ( _preMeshInfo )
4602     _preMeshInfo->FullLoadFromFile();
4603
4604   const SMDS_MeshElement* e = _impl->GetMeshDS()->FindElement(id);
4605   if ( !e )
4606     THROW_SALOME_CORBA_EXCEPTION( "invalid element id", SALOME::BAD_PARAM );
4607
4608   return ( SMESH::GeometryType ) e->GetGeomType();
4609 }
4610
4611 //=============================================================================
4612 /*!
4613  * Returns ID of elements for given submesh
4614  */
4615 //=============================================================================
4616 SMESH::long_array* SMESH_Mesh_i::GetSubMeshElementsId(const CORBA::Long ShapeID)
4617      throw (SALOME::SALOME_Exception)
4618 {
4619   SMESH::long_array_var aResult = new SMESH::long_array();
4620
4621   SMESH_TRY;
4622   if ( _preMeshInfo )
4623     _preMeshInfo->FullLoadFromFile();
4624
4625   SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID);
4626   if(!SM) return aResult._retn();
4627
4628   SMESHDS_SubMesh* SDSM = SM->GetSubMeshDS();
4629   if(!SDSM) return aResult._retn();
4630
4631   aResult->length(SDSM->NbElements());
4632
4633   SMDS_ElemIteratorPtr eIt = SDSM->GetElements();
4634   int i = 0;
4635   while ( eIt->more() ) {
4636     aResult[i++] = eIt->next()->GetID();
4637   }
4638
4639   SMESH_CATCH( SMESH::throwCorbaException );
4640
4641   return aResult._retn();
4642 }
4643
4644 //=============================================================================
4645 /*!
4646  * Returns ID of nodes for given submesh
4647  * If param all==true - returns all nodes, else -
4648  * returns only nodes on shapes.
4649  */
4650 //=============================================================================
4651
4652 SMESH::long_array* SMESH_Mesh_i::GetSubMeshNodesId(const CORBA::Long ShapeID,
4653                                                    CORBA::Boolean    all)
4654   throw (SALOME::SALOME_Exception)
4655 {
4656   SMESH::long_array_var aResult = new SMESH::long_array();
4657
4658   SMESH_TRY;
4659   if ( _preMeshInfo )
4660     _preMeshInfo->FullLoadFromFile();
4661
4662   SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID);
4663   if(!SM) return aResult._retn();
4664
4665   SMESHDS_SubMesh* SDSM = SM->GetSubMeshDS();
4666   if(!SDSM) return aResult._retn();
4667
4668   set<int> theElems;
4669   if( !all || (SDSM->NbElements()==0) ) { // internal nodes or vertex submesh
4670     SMDS_NodeIteratorPtr nIt = SDSM->GetNodes();
4671     while ( nIt->more() ) {
4672       const SMDS_MeshNode* elem = nIt->next();
4673       theElems.insert( elem->GetID() );
4674     }
4675   }
4676   else { // all nodes of submesh elements
4677     SMDS_ElemIteratorPtr eIt = SDSM->GetElements();
4678     while ( eIt->more() ) {
4679       const SMDS_MeshElement* anElem = eIt->next();
4680       SMDS_ElemIteratorPtr nIt = anElem->nodesIterator();
4681       while ( nIt->more() ) {
4682         const SMDS_MeshElement* elem = nIt->next();
4683         theElems.insert( elem->GetID() );
4684       }
4685     }
4686   }
4687
4688   aResult->length(theElems.size());
4689   set<int>::iterator itElem;
4690   int i = 0;
4691   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
4692     aResult[i++] = *itElem;
4693
4694   SMESH_CATCH( SMESH::throwCorbaException );
4695
4696   return aResult._retn();
4697 }
4698
4699 //=============================================================================
4700 /*!
4701  * Returns type of elements for given submesh
4702  */
4703 //=============================================================================
4704
4705 SMESH::ElementType SMESH_Mesh_i::GetSubMeshElementType(const CORBA::Long ShapeID)
4706   throw (SALOME::SALOME_Exception)
4707 {
4708   SMESH::ElementType type = SMESH::ALL;
4709
4710   SMESH_TRY;
4711   if ( _preMeshInfo )
4712     _preMeshInfo->FullLoadFromFile();
4713
4714   SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID);
4715   if(!SM) return SMESH::ALL;
4716
4717   SMESHDS_SubMesh* SDSM = SM->GetSubMeshDS();
4718   if(!SDSM) return SMESH::ALL;
4719
4720   if(SDSM->NbElements()==0)
4721     return (SM->GetSubShape().ShapeType() == TopAbs_VERTEX) ? SMESH::NODE : SMESH::ALL;
4722
4723   SMDS_ElemIteratorPtr eIt = SDSM->GetElements();
4724   const SMDS_MeshElement* anElem = eIt->next();
4725
4726   type = ( SMESH::ElementType ) anElem->GetType();
4727
4728   SMESH_CATCH( SMESH::throwCorbaException );
4729
4730   return type;
4731 }
4732
4733
4734 //=============================================================================
4735 /*!
4736  * Returns pointer to _impl as an integer value. Is called from constructor of SMESH_Client
4737  */
4738 //=============================================================================
4739
4740 CORBA::LongLong SMESH_Mesh_i::GetMeshPtr()
4741 {
4742   if ( _preMeshInfo )
4743     _preMeshInfo->FullLoadFromFile();
4744
4745   CORBA::LongLong pointeur = CORBA::LongLong(_impl);
4746   if ( MYDEBUG ) MESSAGE("CORBA::LongLong SMESH_Mesh_i::GetMeshPtr() "<<pointeur);
4747   return pointeur;
4748 }
4749
4750
4751 //=============================================================================
4752 /*!
4753  * Get XYZ coordinates of node as list of double
4754  * If there is not node for given ID - returns empty list
4755  */
4756 //=============================================================================
4757
4758 SMESH::double_array* SMESH_Mesh_i::GetNodeXYZ(const CORBA::Long id)
4759 {
4760   if ( _preMeshInfo )
4761     _preMeshInfo->FullLoadFromFile();
4762
4763   SMESH::double_array_var aResult = new SMESH::double_array();
4764   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
4765   if ( aMeshDS == NULL )
4766     return aResult._retn();
4767
4768   // find node
4769   const SMDS_MeshNode* aNode = aMeshDS->FindNode(id);
4770   if(!aNode)
4771     return aResult._retn();
4772
4773   // add coordinates
4774   aResult->length(3);
4775   aResult[0] = aNode->X();
4776   aResult[1] = aNode->Y();
4777   aResult[2] = aNode->Z();
4778   return aResult._retn();
4779 }
4780
4781
4782 //=============================================================================
4783 /*!
4784  * For given node returns list of IDs of inverse elements
4785  * If there is not node for given ID - returns empty list
4786  */
4787 //=============================================================================
4788
4789 SMESH::long_array* SMESH_Mesh_i::GetNodeInverseElements(const CORBA::Long  id,
4790                                                         SMESH::ElementType elemType)
4791 {
4792   if ( _preMeshInfo )
4793     _preMeshInfo->FullLoadFromFile();
4794
4795   SMESH::long_array_var aResult = new SMESH::long_array();
4796   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
4797   if ( aMeshDS == NULL )
4798     return aResult._retn();
4799
4800   // find node
4801   const SMDS_MeshNode* aNode = aMeshDS->FindNode( id );
4802   if ( !aNode )
4803     return aResult._retn();
4804
4805   // find inverse elements
4806   SMDSAbs_ElementType type = SMDSAbs_ElementType( elemType );
4807   SMDS_ElemIteratorPtr eIt = aNode->GetInverseElementIterator( type );
4808   aResult->length( aNode->NbInverseElements( type ));
4809   for( int i = 0; eIt->more(); ++i )
4810   {
4811     const SMDS_MeshElement* elem = eIt->next();
4812     aResult[ i ] = elem->GetID();
4813   }
4814   return aResult._retn();
4815 }
4816
4817 //=============================================================================
4818 /*!
4819  * \brief Return position of a node on shape
4820  */
4821 //=============================================================================
4822
4823 SMESH::NodePosition* SMESH_Mesh_i::GetNodePosition(CORBA::Long NodeID)
4824 {
4825   if ( _preMeshInfo )
4826     _preMeshInfo->FullLoadFromFile();
4827
4828   SMESH::NodePosition* aNodePosition = new SMESH::NodePosition();
4829   aNodePosition->shapeID = 0;
4830   aNodePosition->shapeType = GEOM::SHAPE;
4831
4832   SMESHDS_Mesh* mesh = _impl->GetMeshDS();
4833   if ( !mesh ) return aNodePosition;
4834
4835   if ( const SMDS_MeshNode* aNode = mesh->FindNode(NodeID) )
4836   {
4837     if ( SMDS_PositionPtr pos = aNode->GetPosition() )
4838     {
4839       aNodePosition->shapeID = aNode->getshapeId();
4840       switch ( pos->GetTypeOfPosition() ) {
4841       case SMDS_TOP_EDGE:
4842         aNodePosition->shapeType = GEOM::EDGE;
4843         aNodePosition->params.length(1);
4844         aNodePosition->params[0] = SMDS_EdgePositionPtr( pos )->GetUParameter();
4845         break;
4846       case SMDS_TOP_FACE: {
4847         SMDS_FacePositionPtr fPos = pos;
4848         aNodePosition->shapeType = GEOM::FACE;
4849         aNodePosition->params.length(2);
4850         aNodePosition->params[0] = fPos->GetUParameter();
4851         aNodePosition->params[1] = fPos->GetVParameter();
4852         break;
4853       }
4854       case SMDS_TOP_VERTEX:
4855         aNodePosition->shapeType = GEOM::VERTEX;
4856         break;
4857       case SMDS_TOP_3DSPACE:
4858         if ( TopExp_Explorer(_impl->GetShapeToMesh(), TopAbs_SOLID).More() )
4859           aNodePosition->shapeType = GEOM::SOLID;
4860         else if ( TopExp_Explorer(_impl->GetShapeToMesh(), TopAbs_SHELL).More() )
4861           aNodePosition->shapeType = GEOM::SHELL;
4862         break;
4863       default:;
4864       }
4865     }
4866   }
4867   return aNodePosition;
4868 }
4869
4870 //=============================================================================
4871 /*!
4872  * \brief Return position of an element on shape
4873  */
4874 //=============================================================================
4875
4876 SMESH::ElementPosition SMESH_Mesh_i::GetElementPosition(CORBA::Long ElemID)
4877 {
4878   if ( _preMeshInfo )
4879     _preMeshInfo->FullLoadFromFile();
4880
4881   SMESH::ElementPosition anElementPosition;
4882   anElementPosition.shapeID = 0;
4883   anElementPosition.shapeType = GEOM::SHAPE;
4884
4885   SMESHDS_Mesh* mesh = _impl->GetMeshDS();
4886   if ( !mesh ) return anElementPosition;
4887
4888   if ( const SMDS_MeshElement* anElem = mesh->FindElement( ElemID ) )
4889   {
4890     anElementPosition.shapeID = anElem->getshapeId();
4891     const TopoDS_Shape& aSp = mesh->IndexToShape( anElem->getshapeId() );
4892     if ( !aSp.IsNull() ) {
4893       switch ( aSp.ShapeType() ) {
4894       case TopAbs_EDGE:
4895         anElementPosition.shapeType = GEOM::EDGE;
4896         break;
4897       case TopAbs_FACE:
4898         anElementPosition.shapeType = GEOM::FACE;
4899         break;
4900       case TopAbs_VERTEX:
4901         anElementPosition.shapeType = GEOM::VERTEX;
4902         break;
4903       case TopAbs_SOLID:
4904         anElementPosition.shapeType = GEOM::SOLID;
4905         break;
4906       case TopAbs_SHELL:
4907         anElementPosition.shapeType = GEOM::SHELL;
4908         break;
4909       default:;
4910       }
4911     }
4912   }
4913   return anElementPosition;
4914 }
4915
4916 //=============================================================================
4917 /*!
4918  * If given element is node returns IDs of shape from position
4919  * If there is not node for given ID - returns -1
4920  */
4921 //=============================================================================
4922
4923 CORBA::Long SMESH_Mesh_i::GetShapeID(const CORBA::Long id)
4924 {
4925   if ( _preMeshInfo )
4926     _preMeshInfo->FullLoadFromFile();
4927
4928   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
4929   if ( aMeshDS == NULL )
4930     return -1;
4931
4932   // try to find node
4933   const SMDS_MeshNode* aNode = aMeshDS->FindNode(id);
4934   if(aNode) {
4935     return aNode->getshapeId();
4936   }
4937
4938   return -1;
4939 }
4940
4941
4942 //=============================================================================
4943 /*!
4944  * For given element returns ID of result shape after
4945  * ::FindShape() from SMESH_MeshEditor
4946  * If there is not element for given ID - returns -1
4947  */
4948 //=============================================================================
4949
4950 CORBA::Long SMESH_Mesh_i::GetShapeIDForElem(const CORBA::Long id)
4951 {
4952   if ( _preMeshInfo )
4953     _preMeshInfo->FullLoadFromFile();
4954
4955   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
4956   if ( aMeshDS == NULL )
4957     return -1;
4958
4959   // try to find element
4960   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
4961   if(!elem)
4962     return -1;
4963
4964   ::SMESH_MeshEditor aMeshEditor(_impl);
4965   int index = aMeshEditor.FindShape( elem );
4966   if(index>0)
4967     return index;
4968
4969   return -1;
4970 }
4971
4972
4973 //=============================================================================
4974 /*!
4975  * Returns number of nodes for given element
4976  * If there is not element for given ID - returns -1
4977  */
4978 //=============================================================================
4979
4980 CORBA::Long SMESH_Mesh_i::GetElemNbNodes(const CORBA::Long id)
4981 {
4982   if ( _preMeshInfo )
4983     _preMeshInfo->FullLoadFromFile();
4984
4985   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
4986   if ( aMeshDS == NULL ) return -1;
4987   // try to find element
4988   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
4989   if(!elem) return -1;
4990   return elem->NbNodes();
4991 }
4992
4993
4994 //=============================================================================
4995 /*!
4996  * Returns ID of node by given index for given element
4997  * If there is not element for given ID - returns -1
4998  * If there is not node for given index - returns -2
4999  */
5000 //=============================================================================
5001
5002 CORBA::Long SMESH_Mesh_i::GetElemNode(const CORBA::Long id, const CORBA::Long index)
5003 {
5004   if ( _preMeshInfo )
5005     _preMeshInfo->FullLoadFromFile();
5006
5007   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5008   if ( aMeshDS == NULL ) return -1;
5009   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5010   if(!elem) return -1;
5011   if( index>=elem->NbNodes() || index<0 ) return -1;
5012   return elem->GetNode(index)->GetID();
5013 }
5014
5015 //=============================================================================
5016 /*!
5017  * Returns IDs of nodes of given element
5018  */
5019 //=============================================================================
5020
5021 SMESH::long_array* SMESH_Mesh_i::GetElemNodes(const CORBA::Long id)
5022 {
5023   if ( _preMeshInfo )
5024     _preMeshInfo->FullLoadFromFile();
5025
5026   SMESH::long_array_var aResult = new SMESH::long_array();
5027   if ( SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS() )
5028   {
5029     if ( const SMDS_MeshElement* elem = aMeshDS->FindElement(id) )
5030     {
5031       aResult->length( elem->NbNodes() );
5032       for ( CORBA::ULong i = 0; i < aResult->length(); ++i )
5033         if ( const SMDS_MeshNode* n = elem->GetNode( i ))
5034           aResult[ i ] = n->GetID();
5035     }
5036   }
5037   return aResult._retn();
5038 }
5039
5040 //=============================================================================
5041 /*!
5042  * Returns true if given node is medium node
5043  * in given quadratic element
5044  */
5045 //=============================================================================
5046
5047 CORBA::Boolean SMESH_Mesh_i::IsMediumNode(const CORBA::Long ide, const CORBA::Long idn)
5048 {
5049   if ( _preMeshInfo )
5050     _preMeshInfo->FullLoadFromFile();
5051
5052   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5053   if ( aMeshDS == NULL ) return false;
5054   // try to find node
5055   const SMDS_MeshNode* aNode = aMeshDS->FindNode(idn);
5056   if(!aNode) return false;
5057   // try to find element
5058   const SMDS_MeshElement* elem = aMeshDS->FindElement(ide);
5059   if(!elem) return false;
5060
5061   return elem->IsMediumNode(aNode);
5062 }
5063
5064
5065 //=============================================================================
5066 /*!
5067  * Returns true if given node is medium node
5068  * in one of quadratic elements
5069  */
5070 //=============================================================================
5071
5072 CORBA::Boolean SMESH_Mesh_i::IsMediumNodeOfAnyElem(const CORBA::Long idn,
5073                                                    SMESH::ElementType theElemType)
5074 {
5075   if ( _preMeshInfo )
5076     _preMeshInfo->FullLoadFromFile();
5077
5078   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5079   if ( aMeshDS == NULL ) return false;
5080
5081   // try to find node
5082   const SMDS_MeshNode* aNode = aMeshDS->FindNode(idn);
5083   if(!aNode) return false;
5084
5085   SMESH_MesherHelper aHelper( *(_impl) );
5086
5087   SMDSAbs_ElementType aType;
5088   if(theElemType==SMESH::EDGE) aType = SMDSAbs_Edge;
5089   else if(theElemType==SMESH::FACE) aType = SMDSAbs_Face;
5090   else if(theElemType==SMESH::VOLUME) aType = SMDSAbs_Volume;
5091   else aType = SMDSAbs_All;
5092
5093   return aHelper.IsMedium(aNode,aType);
5094 }
5095
5096
5097 //=============================================================================
5098 /*!
5099  * Returns number of edges for given element
5100  */
5101 //=============================================================================
5102
5103 CORBA::Long SMESH_Mesh_i::ElemNbEdges(const CORBA::Long id)
5104 {
5105   if ( _preMeshInfo )
5106     _preMeshInfo->FullLoadFromFile();
5107
5108   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5109   if ( aMeshDS == NULL ) return -1;
5110   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5111   if(!elem) return -1;
5112   return elem->NbEdges();
5113 }
5114
5115
5116 //=============================================================================
5117 /*!
5118  * Returns number of faces for given element
5119  */
5120 //=============================================================================
5121
5122 CORBA::Long SMESH_Mesh_i::ElemNbFaces(const CORBA::Long id)
5123 {
5124   if ( _preMeshInfo )
5125     _preMeshInfo->FullLoadFromFile();
5126
5127   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5128   if ( aMeshDS == NULL ) return -1;
5129   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5130   if(!elem) return -1;
5131   return elem->NbFaces();
5132 }
5133
5134 //=======================================================================
5135 //function : GetElemFaceNodes
5136 //purpose  : Returns nodes of given face (counted from zero) for given element.
5137 //=======================================================================
5138
5139 SMESH::long_array* SMESH_Mesh_i::GetElemFaceNodes(CORBA::Long  elemId,
5140                                                   CORBA::Short faceIndex)
5141 {
5142   if ( _preMeshInfo )
5143     _preMeshInfo->FullLoadFromFile();
5144
5145   SMESH::long_array_var aResult = new SMESH::long_array();
5146   if ( SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS() )
5147   {
5148     if ( const SMDS_MeshElement* elem = aMeshDS->FindElement(elemId) )
5149     {
5150       SMDS_VolumeTool vtool( elem, /*skipCentralNodes = */false );
5151       if ( faceIndex < vtool.NbFaces() )
5152       {
5153         aResult->length( vtool.NbFaceNodes( faceIndex ));
5154         const SMDS_MeshNode** nn = vtool.GetFaceNodes( faceIndex );
5155         for ( CORBA::ULong i = 0; i < aResult->length(); ++i )
5156           aResult[ i ] = nn[ i ]->GetID();
5157       }
5158     }
5159   }
5160   return aResult._retn();
5161 }
5162
5163 //=======================================================================
5164 //function : GetFaceNormal
5165 //purpose  : Returns three components of normal of given mesh face.
5166 //=======================================================================
5167
5168 SMESH::double_array* SMESH_Mesh_i::GetFaceNormal(CORBA::Long    elemId,
5169                                                  CORBA::Boolean normalized)
5170 {
5171   if ( _preMeshInfo )
5172     _preMeshInfo->FullLoadFromFile();
5173
5174   SMESH::double_array_var aResult = new SMESH::double_array();
5175
5176   if ( SMESHDS_Mesh* mesh = _impl->GetMeshDS() )
5177   {
5178     gp_XYZ normal;
5179     if ( SMESH_MeshAlgos::FaceNormal( mesh->FindElement(elemId), normal, normalized ))
5180     {
5181       aResult->length( 3 );
5182       aResult[ 0 ] = normal.X();
5183       aResult[ 1 ] = normal.Y();
5184       aResult[ 2 ] = normal.Z();
5185     }
5186   }
5187   return aResult._retn();
5188 }
5189
5190 //=======================================================================
5191 //function : FindElementByNodes
5192 //purpose  : Returns an element based on all given nodes.
5193 //=======================================================================
5194
5195 CORBA::Long SMESH_Mesh_i::FindElementByNodes(const SMESH::long_array& nodes)
5196 {
5197   if ( _preMeshInfo )
5198     _preMeshInfo->FullLoadFromFile();
5199
5200   CORBA::Long elemID(0);
5201   if ( SMESHDS_Mesh* mesh = _impl->GetMeshDS() )
5202   {
5203     vector< const SMDS_MeshNode * > nn( nodes.length() );
5204     for ( CORBA::ULong i = 0; i < nodes.length(); ++i )
5205       if ( !( nn[i] = mesh->FindNode( nodes[i] )))
5206         return elemID;
5207
5208     const SMDS_MeshElement* elem = mesh->FindElement( nn, SMDSAbs_All, /*noMedium=*/false );
5209     if ( !elem && ( _impl->NbEdges  ( ORDER_QUADRATIC ) ||
5210                     _impl->NbFaces  ( ORDER_QUADRATIC ) ||
5211                     _impl->NbVolumes( ORDER_QUADRATIC )))
5212       elem = mesh->FindElement( nn, SMDSAbs_All, /*noMedium=*/true );
5213
5214     if ( elem ) elemID = CORBA::Long( elem->GetID() );
5215   }
5216   return elemID;
5217 }
5218
5219 //================================================================================
5220 /*!
5221  * \brief Return elements including all given nodes.
5222  */
5223 //================================================================================
5224
5225 SMESH::long_array* SMESH_Mesh_i::GetElementsByNodes(const SMESH::long_array& nodes,
5226                                                     SMESH::ElementType       elemType)
5227 {
5228   if ( _preMeshInfo )
5229     _preMeshInfo->FullLoadFromFile();
5230
5231   SMESH::long_array_var result = new SMESH::long_array();
5232
5233   if ( SMESHDS_Mesh* mesh = _impl->GetMeshDS() )
5234   {
5235     vector< const SMDS_MeshNode * > nn( nodes.length() );
5236     for ( CORBA::ULong i = 0; i < nodes.length(); ++i )
5237       nn[i] = mesh->FindNode( nodes[i] );
5238
5239     std::vector<const SMDS_MeshElement *> elems;
5240     mesh->GetElementsByNodes( nn, elems, (SMDSAbs_ElementType) elemType );
5241     result->length( elems.size() );
5242     for ( size_t i = 0; i < elems.size(); ++i )
5243       result[i] = elems[i]->GetID();
5244   }
5245   return result._retn();
5246 }
5247
5248 //=============================================================================
5249 /*!
5250  * Returns true if given element is polygon
5251  */
5252 //=============================================================================
5253
5254 CORBA::Boolean SMESH_Mesh_i::IsPoly(const CORBA::Long id)
5255 {
5256   if ( _preMeshInfo )
5257     _preMeshInfo->FullLoadFromFile();
5258
5259   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5260   if ( aMeshDS == NULL ) return false;
5261   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5262   if(!elem) return false;
5263   return elem->IsPoly();
5264 }
5265
5266
5267 //=============================================================================
5268 /*!
5269  * Returns true if given element is quadratic
5270  */
5271 //=============================================================================
5272
5273 CORBA::Boolean SMESH_Mesh_i::IsQuadratic(const CORBA::Long id)
5274 {
5275   if ( _preMeshInfo )
5276     _preMeshInfo->FullLoadFromFile();
5277
5278   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5279   if ( aMeshDS == NULL ) return false;
5280   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5281   if(!elem) return false;
5282   return elem->IsQuadratic();
5283 }
5284
5285 //=============================================================================
5286 /*!
5287  * Returns diameter of ball discrete element or zero in case of an invalid \a id
5288  */
5289 //=============================================================================
5290
5291 CORBA::Double SMESH_Mesh_i::GetBallDiameter(CORBA::Long id)
5292 {
5293   if ( _preMeshInfo )
5294     _preMeshInfo->FullLoadFromFile();
5295
5296   if ( const SMDS_BallElement* ball =
5297        SMDS_Mesh::DownCast<SMDS_BallElement>( _impl->GetMeshDS()->FindElement( id )))
5298     return ball->GetDiameter();
5299
5300   return 0;
5301 }
5302
5303 //=============================================================================
5304 /*!
5305  * Returns bary center for given element
5306  */
5307 //=============================================================================
5308
5309 SMESH::double_array* SMESH_Mesh_i::BaryCenter(const CORBA::Long id)
5310 {
5311   if ( _preMeshInfo )
5312     _preMeshInfo->FullLoadFromFile();
5313
5314   SMESH::double_array_var aResult = new SMESH::double_array();
5315   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5316   if ( aMeshDS == NULL )
5317     return aResult._retn();
5318
5319   const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
5320   if(!elem)
5321     return aResult._retn();
5322
5323   if(elem->GetType()==SMDSAbs_Volume) {
5324     SMDS_VolumeTool aTool;
5325     if(aTool.Set(elem)) {
5326       aResult->length(3);
5327       if (!aTool.GetBaryCenter( aResult[0], aResult[1], aResult[2]) )
5328         aResult->length(0);
5329     }
5330   }
5331   else {
5332     SMDS_ElemIteratorPtr anIt = elem->nodesIterator();
5333     int nbn = 0;
5334     double x=0., y=0., z=0.;
5335     for(; anIt->more(); ) {
5336       nbn++;
5337       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>(anIt->next());
5338       x += aNode->X();
5339       y += aNode->Y();
5340       z += aNode->Z();
5341     }
5342     if(nbn>0) {
5343       // add coordinates
5344       aResult->length(3);
5345       aResult[0] = x/nbn;
5346       aResult[1] = y/nbn;
5347       aResult[2] = z/nbn;
5348     }
5349   }
5350
5351   return aResult._retn();
5352 }
5353
5354 //================================================================================
5355 /*!
5356  * \brief Create a group of elements preventing computation of a sub-shape
5357  */
5358 //================================================================================
5359
5360 SMESH::ListOfGroups*
5361 SMESH_Mesh_i::MakeGroupsOfBadInputElements( int         theSubShapeID,
5362                                             const char* theGroupName )
5363   throw ( SALOME::SALOME_Exception )
5364 {
5365   Unexpect aCatch(SALOME_SalomeException);
5366
5367   if ( !theGroupName || strlen( theGroupName) == 0 )
5368     THROW_SALOME_CORBA_EXCEPTION( "empty group name",SALOME::BAD_PARAM );
5369
5370   SMESH::ListOfGroups_var groups = new SMESH::ListOfGroups;
5371   ::SMESH_MeshEditor::ElemFeatures elemType;
5372
5373   // submesh by subshape id
5374   if ( !_impl->HasShapeToMesh() ) theSubShapeID = 1;
5375   if ( SMESH_subMesh * sm = _impl->GetSubMeshContaining( theSubShapeID ))
5376   {
5377     // compute error
5378     SMESH_ComputeErrorPtr error = sm->GetComputeError();
5379     if ( error && error->HasBadElems() )
5380     {
5381       // sort bad elements by type
5382       vector< const SMDS_MeshElement* > elemsByType[ SMDSAbs_NbElementTypes ];
5383       const list<const SMDS_MeshElement*>& badElems =
5384         static_cast<SMESH_BadInputElements*>( error.get() )->myBadElements;
5385       list<const SMDS_MeshElement*>::const_iterator elemIt  = badElems.begin();
5386       list<const SMDS_MeshElement*>::const_iterator elemEnd = badElems.end();
5387       for ( ; elemIt != elemEnd; ++elemIt )
5388       {
5389         const SMDS_MeshElement* elem = *elemIt;
5390         if ( !elem ) continue;
5391
5392         if ( elem->GetID() < 1 )
5393         {
5394           // elem is a temporary element, make a real element
5395           vector< const SMDS_MeshNode* > nodes;
5396           SMDS_NodeIteratorPtr nIt = elem->nodeIterator();
5397           while ( nIt->more() && elem )
5398           {
5399             nodes.push_back( nIt->next() );
5400             if ( nodes.back()->GetID() < 1 )
5401               elem = 0;  // a temporary element on temporary nodes
5402           }
5403           if ( elem )
5404           {
5405             ::SMESH_MeshEditor editor( _impl );
5406             elem = editor.AddElement( nodes, elemType.Init( elem ));
5407           }
5408         }
5409         if ( elem )
5410           elemsByType[ elem->GetType() ].push_back( elem );
5411       }
5412
5413       // how many groups to create?
5414       int nbTypes = 0;
5415       for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
5416         nbTypes += int( !elemsByType[ i ].empty() );
5417       groups->length( nbTypes );
5418
5419       // create groups
5420       for ( int i = 0, iG = -1; i < SMDSAbs_NbElementTypes; ++i )
5421       {
5422         vector< const SMDS_MeshElement* >& elems = elemsByType[ i ];
5423         if ( elems.empty() ) continue;
5424
5425         groups[ ++iG ] = createGroup( SMESH::ElementType(i), theGroupName );
5426         if ( _gen_i->CanPublishInStudy( groups[ iG ] ))
5427         {
5428           SMESH::SMESH_Mesh_var mesh = _this();
5429           SALOMEDS::SObject_wrap aSO =
5430             _gen_i->PublishGroup( mesh, groups[ iG ],
5431                                  GEOM::GEOM_Object::_nil(), theGroupName);
5432         }
5433         SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( groups[ iG ]);
5434         if ( !grp_i ) continue;
5435
5436         if ( SMESHDS_Group*  grpDS = dynamic_cast< SMESHDS_Group* >( grp_i->GetGroupDS() ))
5437           for ( size_t iE = 0; iE < elems.size(); ++iE )
5438             grpDS->SMDSGroup().Add( elems[ iE ]);
5439       }
5440     }
5441   }
5442
5443   return groups._retn();
5444 }
5445
5446 //=============================================================================
5447 /*!
5448  * Create and publish group servants if any groups were imported or created anyhow
5449  */
5450 //=============================================================================
5451
5452 void SMESH_Mesh_i::CreateGroupServants()
5453 {
5454   SMESH::SMESH_Mesh_var aMesh = _this();
5455
5456   set<int> addedIDs;
5457   ::SMESH_Mesh::GroupIteratorPtr groupIt = _impl->GetGroups();
5458   while ( groupIt->more() )
5459   {
5460     ::SMESH_Group* group = groupIt->next();
5461     int             anId = group->GetID();
5462
5463     map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.find(anId);
5464     if ( it != _mapGroups.end() && !CORBA::is_nil( it->second ))
5465       continue;
5466     addedIDs.insert( anId );
5467
5468     SMESH_GroupBase_i* aGroupImpl;
5469     TopoDS_Shape       shape;
5470     if ( SMESHDS_GroupOnGeom* groupOnGeom =
5471          dynamic_cast<SMESHDS_GroupOnGeom*>( group->GetGroupDS() ))
5472     {
5473       aGroupImpl = new SMESH_GroupOnGeom_i( SMESH_Gen_i::GetPOA(), this, anId );
5474       shape      = groupOnGeom->GetShape();
5475     }
5476     else {
5477       aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId );
5478     }
5479
5480     SMESH::SMESH_GroupBase_var groupVar = aGroupImpl->_this();
5481     _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( groupVar );
5482     aGroupImpl->Register();
5483
5484     // register CORBA object for persistence
5485     int nextId = _gen_i->RegisterObject( groupVar );
5486     if(MYDEBUG) { MESSAGE( "Add group to map with id = "<< nextId); }
5487     else        { nextId = 0; } // avoid "unused variable" warning in release mode
5488
5489     // publishing the groups in the study
5490     GEOM::GEOM_Object_var shapeVar = _gen_i->ShapeToGeomObject( shape );
5491     _gen_i->PublishGroup( aMesh, groupVar, shapeVar, group->GetName());
5492   }
5493   if ( !addedIDs.empty() )
5494   {
5495     // python dump
5496     set<int>::iterator id = addedIDs.begin();
5497     for ( ; id != addedIDs.end(); ++id )
5498     {
5499       map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.find(*id);
5500       int i = std::distance( _mapGroups.begin(), it );
5501       TPythonDump() << it->second << " = " << aMesh << ".GetGroups()[ "<< i << " ]";
5502     }
5503   }
5504 }
5505
5506 //=============================================================================
5507 /*!
5508  * \brief Return true if all sub-meshes are computed OK - to update an icon
5509  */
5510 //=============================================================================
5511
5512 bool SMESH_Mesh_i::IsComputedOK()
5513 {
5514   return _impl->IsComputedOK();
5515 }
5516
5517 //=============================================================================
5518 /*!
5519  * \brief Return groups cantained in _mapGroups by their IDs
5520  */
5521 //=============================================================================
5522
5523 SMESH::ListOfGroups* SMESH_Mesh_i::GetGroups(const list<int>& groupIDs) const
5524 {
5525   int nbGroups = groupIDs.size();
5526   SMESH::ListOfGroups_var aList = new SMESH::ListOfGroups();
5527   aList->length( nbGroups );
5528
5529   list<int>::const_iterator ids = groupIDs.begin();
5530   for ( nbGroups = 0; ids != groupIDs.end(); ++ids )
5531   {
5532     map<int, SMESH::SMESH_GroupBase_ptr>::const_iterator it = _mapGroups.find( *ids );
5533     if ( it != _mapGroups.end() && !CORBA::is_nil( it->second ))
5534       aList[nbGroups++] = SMESH::SMESH_GroupBase::_duplicate( it->second );
5535   }
5536   aList->length( nbGroups );
5537   return aList._retn();
5538 }
5539
5540 //=============================================================================
5541 /*!
5542  * \brief Return information about imported file
5543  */
5544 //=============================================================================
5545
5546 SMESH::MedFileInfo* SMESH_Mesh_i::GetMEDFileInfo()
5547 {
5548   SMESH::MedFileInfo_var res( _medFileInfo );
5549   if ( !res.operator->() ) {
5550     res = new SMESH::MedFileInfo;
5551     res->fileName = "";
5552     res->fileSize = res->major = res->minor = res->release = -1;
5553   }
5554   return res._retn();
5555 }
5556
5557 //=======================================================================
5558 //function : FileInfoToString
5559 //purpose  : Persistence of file info
5560 //=======================================================================
5561
5562 std::string SMESH_Mesh_i::FileInfoToString()
5563 {
5564   std::string s;
5565   if ( &_medFileInfo.in() && _medFileInfo->fileName[0] )
5566   {
5567     s = SMESH_Comment( _medFileInfo->fileSize )
5568       << " " << _medFileInfo->major
5569       << " " << _medFileInfo->minor
5570       << " " << _medFileInfo->release
5571       << " " << _medFileInfo->fileName;
5572   }
5573   return s;
5574 }
5575
5576 //=======================================================================
5577 //function : FileInfoFromString
5578 //purpose  : Persistence of file info
5579 //=======================================================================
5580
5581 void SMESH_Mesh_i::FileInfoFromString(const std::string& info)
5582 {
5583   std::string size, major, minor, release, fileName;
5584   std::istringstream is(info);
5585   is >> size >> major >> minor >> release;
5586   fileName = info.data() + ( size.size()   + 1 +
5587                              major.size()  + 1 +
5588                              minor.size()  + 1 +
5589                              release.size()+ 1 );
5590
5591   _medFileInfo           = new SMESH::MedFileInfo();
5592   _medFileInfo->fileName = fileName.c_str();
5593   _medFileInfo->fileSize = atoi( size.c_str() );
5594   _medFileInfo->major    = atoi( major.c_str() );
5595   _medFileInfo->minor    = atoi( minor.c_str() );
5596   _medFileInfo->release  = atoi( release.c_str() );
5597 }
5598
5599 //=============================================================================
5600 /*!
5601  * \brief Pass names of mesh groups from study to mesh DS
5602  */
5603 //=============================================================================
5604
5605 void SMESH_Mesh_i::checkGroupNames()
5606 {
5607   int nbGrp = NbGroups();
5608   if ( !nbGrp )
5609     return;
5610
5611   SMESH::ListOfGroups* grpList = 0;
5612   // avoid dump of "GetGroups"
5613   {
5614     // store python dump into a local variable inside local scope
5615     SMESH::TPythonDump pDump; // do not delete this line of code
5616     grpList = GetGroups();
5617   }
5618
5619   for ( int gIndx = 0; gIndx < nbGrp; gIndx++ ) {
5620     SMESH::SMESH_GroupBase_ptr aGrp = (*grpList)[ gIndx ];
5621     if ( !aGrp )
5622       continue;
5623     SALOMEDS::SObject_wrap aGrpSO = _gen_i->ObjectToSObject( aGrp );
5624     if ( aGrpSO->_is_nil() )
5625       continue;
5626     // correct name of the mesh group if necessary
5627     const char* guiName = aGrpSO->GetName();
5628     if ( strcmp(guiName, aGrp->GetName()) )
5629       aGrp->SetName( guiName );
5630   }
5631 }
5632
5633 //=============================================================================
5634 /*!
5635  * \brief Sets list of notebook variables used for Mesh operations separated by ":" symbol
5636  */
5637 //=============================================================================
5638 void SMESH_Mesh_i::SetParameters(const char* theParameters)
5639 {
5640   SMESH_Gen_i::GetSMESHGen()->UpdateParameters( CORBA::Object_var( _this() ).in(),
5641                                                 theParameters );
5642 }
5643
5644 //=============================================================================
5645 /*!
5646  * \brief Returns list of notebook variables used for Mesh operations separated by ":" symbol
5647  */
5648 //=============================================================================
5649
5650 char* SMESH_Mesh_i::GetParameters()
5651 {
5652   return SMESH_Gen_i::GetSMESHGen()->GetParameters( SMESH::SMESH_Mesh_var( _this()) );
5653 }
5654
5655 //=============================================================================
5656 /*!
5657  * \brief Returns list of notebook variables used for last Mesh operation
5658  */
5659 //=============================================================================
5660 SMESH::string_array* SMESH_Mesh_i::GetLastParameters()
5661 {
5662   SMESH::string_array_var aResult = new SMESH::string_array();
5663   SMESH_Gen_i *gen = SMESH_Gen_i::GetSMESHGen();
5664   if(gen) {
5665     CORBA::String_var aParameters = GetParameters();
5666     SALOMEDS::ListOfListOfStrings_var aSections = SMESH_Gen_i::getStudyServant()->ParseVariables(aParameters);
5667     if ( aSections->length() > 0 ) {
5668       SALOMEDS::ListOfStrings aVars = aSections[ aSections->length() - 1 ];
5669       aResult->length( aVars.length() );
5670       for ( CORBA::ULong i = 0;i < aVars.length(); i++ )
5671         aResult[i] = CORBA::string_dup( aVars[i] );
5672     }
5673   }
5674   return aResult._retn();
5675 }
5676
5677 //=======================================================================
5678 //function : GetTypes
5679 //purpose  : Returns types of elements it contains
5680 //=======================================================================
5681
5682 SMESH::array_of_ElementType* SMESH_Mesh_i::GetTypes()
5683 {
5684   if ( _preMeshInfo )
5685     return _preMeshInfo->GetTypes();
5686
5687   SMESH::array_of_ElementType_var types = new SMESH::array_of_ElementType;
5688
5689   types->length( 5 );
5690   int nbTypes = 0;
5691   if (_impl->NbEdges())      types[nbTypes++] = SMESH::EDGE;
5692   if (_impl->NbFaces())      types[nbTypes++] = SMESH::FACE;
5693   if (_impl->NbVolumes())    types[nbTypes++] = SMESH::VOLUME;
5694   if (_impl->Nb0DElements()) types[nbTypes++] = SMESH::ELEM0D;
5695   if (_impl->NbBalls())      types[nbTypes++] = SMESH::BALL;
5696   if (_impl->NbNodes() &&
5697       nbTypes == 0 )         types[nbTypes++] = SMESH::NODE;
5698   types->length( nbTypes );
5699
5700   return types._retn();
5701 }
5702
5703 //=======================================================================
5704 //function : GetMesh
5705 //purpose  : Returns self
5706 //=======================================================================
5707
5708 SMESH::SMESH_Mesh_ptr SMESH_Mesh_i::GetMesh()
5709 {
5710   return SMESH::SMESH_Mesh::_duplicate( _this() );
5711 }
5712
5713 //=======================================================================
5714 //function : IsMeshInfoCorrect
5715 //purpose  : * Returns false if GetMeshInfo() returns incorrect information that may
5716 //           * happen if mesh data is not yet fully loaded from the file of study.
5717 //=======================================================================
5718
5719 bool SMESH_Mesh_i::IsMeshInfoCorrect()
5720 {
5721   return _preMeshInfo ? _preMeshInfo->IsMeshInfoCorrect() : true;
5722 }
5723
5724 //=============================================================================
5725 /*!
5726  * \brief Returns number of mesh elements per each \a EntityType
5727  */
5728 //=============================================================================
5729
5730 SMESH::long_array* SMESH_Mesh_i::GetMeshInfo()
5731 {
5732   if ( _preMeshInfo )
5733     return _preMeshInfo->GetMeshInfo();
5734
5735   SMESH::long_array_var aRes = new SMESH::long_array();
5736   aRes->length(SMESH::Entity_Last);
5737   for (int i = SMESH::Entity_Node; i < SMESH::Entity_Last; i++)
5738     aRes[i] = 0;
5739   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
5740   if (!aMeshDS)
5741     return aRes._retn();
5742   const SMDS_MeshInfo& aMeshInfo = aMeshDS->GetMeshInfo();
5743   for (int i = SMESH::Entity_Node; i < SMESH::Entity_Last; i++)
5744     aRes[i] = aMeshInfo.NbEntities((SMDSAbs_EntityType)i);
5745   return aRes._retn();
5746 }
5747
5748 //=============================================================================
5749 /*!
5750  * \brief Returns number of mesh elements per each \a ElementType
5751  */
5752 //=============================================================================
5753
5754 SMESH::long_array* SMESH_Mesh_i::GetNbElementsByType()
5755 {
5756   SMESH::long_array_var aRes = new SMESH::long_array();
5757   aRes->length(SMESH::NB_ELEMENT_TYPES);
5758   for (int i = 0; i < SMESH::NB_ELEMENT_TYPES; i++)
5759     aRes[ i ] = 0;
5760
5761   const SMDS_MeshInfo* meshInfo = 0;
5762   if ( _preMeshInfo )
5763     meshInfo = _preMeshInfo;
5764   else if ( SMESHDS_Mesh* meshDS = _impl->GetMeshDS() )
5765     meshInfo = & meshDS->GetMeshInfo();
5766
5767   if (meshInfo)
5768     for (int i = 0; i < SMESH::NB_ELEMENT_TYPES; i++)
5769       aRes[i] = meshInfo->NbElements((SMDSAbs_ElementType)i);
5770
5771   return aRes._retn();
5772 }
5773
5774 //=============================================================================
5775 /*
5776  * Collect statistic of mesh elements given by iterator
5777  */
5778 //=============================================================================
5779
5780 void SMESH_Mesh_i::CollectMeshInfo(const SMDS_ElemIteratorPtr theItr,
5781                                    SMESH::long_array&         theInfo)
5782 {
5783   if (!theItr) return;
5784   while (theItr->more())
5785     theInfo[ theItr->next()->GetEntityType() ]++;
5786 }
5787 //=============================================================================
5788 /*
5789  * Returns mesh unstructed grid information.
5790  */
5791 //=============================================================================
5792
5793 SALOMEDS::TMPFile* SMESH_Mesh_i::GetVtkUgStream()
5794 {
5795   SALOMEDS::TMPFile_var SeqFile;
5796   if ( SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS() ) {
5797     SMDS_UnstructuredGrid* aGrid = aMeshDS->GetGrid();
5798     if(aGrid) {
5799       vtkUnstructuredGridWriter* aWriter = vtkUnstructuredGridWriter::New();
5800       aWriter->WriteToOutputStringOn();
5801       aWriter->SetInputData(aGrid);
5802       aWriter->SetFileTypeToBinary();
5803       aWriter->Write();
5804       char* str = aWriter->GetOutputString();
5805       int size = aWriter->GetOutputStringLength();
5806
5807       //Allocate octet buffer of required size
5808       CORBA::Octet* OctetBuf = SALOMEDS::TMPFile::allocbuf(size);
5809       //Copy ostrstream content to the octet buffer
5810       memcpy(OctetBuf, str, size);
5811       //Create and return TMPFile
5812       SeqFile = new SALOMEDS::TMPFile(size, size, OctetBuf, 1);
5813       aWriter->Delete();
5814     }
5815   }
5816   return SeqFile._retn();
5817 }
5818
5819 //=============================================================================
5820 namespace /* Iterators used in SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_var obj,
5821            *                                             SMESH::ElementType        type) */
5822 {
5823   using namespace SMESH::Controls;
5824   //-----------------------------------------------------------------------------
5825   struct PredicateIterator : public SMDS_ElemIterator
5826   {
5827     SMDS_ElemIteratorPtr    _elemIter;
5828     PredicatePtr            _predicate;
5829     const SMDS_MeshElement* _elem;
5830     SMDSAbs_ElementType     _type;
5831
5832     PredicateIterator( SMDS_ElemIteratorPtr iterator,
5833                        PredicatePtr         predicate,
5834                        SMDSAbs_ElementType  type):
5835       _elemIter(iterator), _predicate(predicate), _type(type)
5836     {
5837       next();
5838     }
5839     virtual bool more()
5840     {
5841       return _elem;
5842     }
5843     virtual const SMDS_MeshElement* next()
5844     {
5845       const SMDS_MeshElement* res = _elem;
5846       _elem = 0;
5847       while ( _elemIter->more() && !_elem )
5848       {
5849         if ((_elem = _elemIter->next()) &&
5850             (( _type != SMDSAbs_All && _type != _elem->GetType() ) ||
5851              ( !_predicate->IsSatisfy( _elem->GetID() ))))
5852           _elem = 0;
5853       }
5854       return res;
5855     }
5856   };
5857
5858   //-----------------------------------------------------------------------------
5859   struct IDSourceIterator : public SMDS_ElemIterator
5860   {
5861     const CORBA::Long*        _idPtr;
5862     const CORBA::Long*        _idEndPtr;
5863     SMESH::long_array_var     _idArray;
5864     const SMDS_Mesh*          _mesh;
5865     const SMDSAbs_ElementType _type;
5866     const SMDS_MeshElement*   _elem;
5867
5868     IDSourceIterator( const SMDS_Mesh*    mesh,
5869                       const CORBA::Long*  ids,
5870                       const int           nbIds,
5871                       SMDSAbs_ElementType type):
5872       _idPtr( ids ), _idEndPtr( ids + nbIds ), _mesh( mesh ), _type( type ), _elem( 0 )
5873     {
5874       if ( _idPtr && nbIds && _mesh )
5875         next();
5876     }
5877     IDSourceIterator( const SMDS_Mesh*    mesh,
5878                       SMESH::long_array*  idArray,
5879                       SMDSAbs_ElementType type):
5880       _idPtr( 0 ), _idEndPtr( 0 ), _idArray( idArray), _mesh( mesh ), _type( type ), _elem( 0 )
5881     {
5882       if ( idArray && _mesh )
5883       {
5884         _idPtr    = &_idArray[0];
5885         _idEndPtr = _idPtr + _idArray->length();
5886         next();
5887       }
5888     }
5889     virtual bool more()
5890     {
5891       return _elem;
5892     }
5893     virtual const SMDS_MeshElement* next()
5894     {
5895       const SMDS_MeshElement* res = _elem;
5896       _elem = 0;
5897       while ( _idPtr < _idEndPtr && !_elem )
5898       {
5899         if ( _type == SMDSAbs_Node )
5900         {
5901           _elem = _mesh->FindNode( *_idPtr++ );
5902         }
5903         else if ((_elem = _mesh->FindElement( *_idPtr++ )) &&
5904                  (_elem->GetType() != _type && _type != SMDSAbs_All ))
5905         {
5906           _elem = 0;
5907         }
5908       }
5909       return res;
5910     }
5911   };
5912   //-----------------------------------------------------------------------------
5913
5914   struct NodeOfElemIterator : public SMDS_ElemIterator
5915   {
5916     TColStd_MapOfInteger    _checkedNodeIDs;
5917     SMDS_ElemIteratorPtr    _elemIter;
5918     SMDS_ElemIteratorPtr    _nodeIter;
5919     const SMDS_MeshElement* _node;
5920
5921     NodeOfElemIterator( SMDS_ElemIteratorPtr iter ): _elemIter( iter ), _node( 0 )
5922     {
5923       if ( _elemIter && _elemIter->more() )
5924       {
5925         _nodeIter = _elemIter->next()->nodesIterator();
5926         next();
5927       }
5928     }
5929     virtual bool more()
5930     {
5931       return _node;
5932     }
5933     virtual const SMDS_MeshElement* next()
5934     {
5935       const SMDS_MeshElement* res = _node;
5936       _node = 0;
5937       while ( !_node && ( _elemIter->more() || _nodeIter->more() ))
5938       {
5939         if ( _nodeIter->more() )
5940         {
5941           _node = _nodeIter->next();
5942           if ( !_checkedNodeIDs.Add( _node->GetID() ))
5943             _node = 0;
5944         }
5945         else
5946         {
5947           _nodeIter = _elemIter->next()->nodesIterator();
5948         }
5949       }
5950       return res;
5951     }
5952   };
5953 }
5954
5955 //=============================================================================
5956 /*
5957  * Return iterator on elements of given type in given object
5958  */
5959 //=============================================================================
5960
5961 SMDS_ElemIteratorPtr SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_ptr theObject,
5962                                                SMESH::ElementType        theType)
5963 {
5964   SMDS_ElemIteratorPtr  elemIt;
5965   bool                  typeOK = ( theType == SMESH::ALL );
5966   SMDSAbs_ElementType elemType = SMDSAbs_ElementType( theType );
5967
5968   SMESH::SMESH_Mesh_var meshVar = theObject->GetMesh();
5969   SMESH_Mesh_i*          mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( meshVar );
5970   if ( !mesh_i ) return elemIt;
5971   SMESHDS_Mesh*          meshDS = mesh_i->GetImpl().GetMeshDS();
5972
5973   if ( SMESH::DownCast<SMESH_Mesh_i*>( theObject ))
5974   {
5975     elemIt = meshDS->elementsIterator( elemType );
5976     typeOK = true;
5977   }
5978   else if ( SMESH_subMesh_i* submesh_i = SMESH::DownCast<SMESH_subMesh_i*>( theObject ))
5979   {
5980     SMESHDS_SubMesh* sm = ((SMESHDS_Mesh*) meshDS)->MeshElements( submesh_i->GetId() );
5981     if ( sm )
5982     {
5983       elemIt = sm->GetElements();
5984       if ( elemType != SMDSAbs_Node && elemType != SMDSAbs_All )
5985       {
5986         typeOK = ( elemIt && elemIt->more() && elemIt->next()->GetType() == elemType );
5987         elemIt = typeOK ? sm->GetElements() : SMDS_ElemIteratorPtr();
5988       }
5989     }
5990   }
5991   else if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( theObject ))
5992   {
5993     SMESHDS_GroupBase* groupDS = group_i->GetGroupDS();
5994     if ( groupDS && ( elemType == groupDS->GetType()  ||
5995                       elemType == SMDSAbs_Node ||
5996                       elemType == SMDSAbs_All ))
5997     {
5998       elemIt = groupDS->GetElements();
5999       typeOK = ( groupDS->GetType() == elemType || elemType == SMDSAbs_All );
6000     }
6001   }
6002   else if ( SMESH::Filter_i* filter_i = SMESH::DownCast<SMESH::Filter_i*>( theObject ))
6003   {
6004     if ( filter_i->GetElementType() == theType ||
6005          filter_i->GetElementType() == SMESH::ALL ||
6006          elemType == SMDSAbs_Node ||
6007          elemType == SMDSAbs_All)
6008     {
6009       SMESH::Predicate_i* pred_i = filter_i->GetPredicate_i();
6010       if ( pred_i && pred_i->GetPredicate() )
6011       {
6012         SMDSAbs_ElementType filterType = SMDSAbs_ElementType( filter_i->GetElementType() );
6013         SMDS_ElemIteratorPtr allElemIt = meshDS->elementsIterator( filterType );
6014         SMDSAbs_ElementType   iterType = elemType == SMDSAbs_Node ? filterType : elemType;
6015         elemIt = SMDS_ElemIteratorPtr
6016           ( new PredicateIterator( allElemIt, pred_i->GetPredicate(), iterType ));
6017         typeOK = ( elemType == SMDSAbs_Node ? filterType == SMDSAbs_Node : elemIt->more() );
6018       }
6019     }
6020   }
6021   else
6022   {
6023     SMESH::array_of_ElementType_var types = theObject->GetTypes();
6024     const bool                    isNodes = ( types->length() == 1 && types[0] == SMESH::NODE );
6025     if ( isNodes && elemType != SMDSAbs_Node && elemType != SMDSAbs_All )
6026       return elemIt;
6027     SMDSAbs_ElementType iterType = isNodes ? SMDSAbs_Node : elemType;
6028     if ( SMESH_MeshEditor_i::IsTemporaryIDSource( theObject ))
6029     {
6030       int nbIds;
6031       if ( CORBA::Long* ids = SMESH_MeshEditor_i::GetTemporaryIDs( theObject, nbIds ))
6032         elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids, nbIds, iterType ));
6033     }
6034     else
6035     {
6036       SMESH::long_array_var ids = theObject->GetIDs();
6037       elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids._retn(), iterType ));
6038     }
6039     typeOK = ( isNodes == ( elemType == SMDSAbs_Node )) || ( elemType == SMDSAbs_All );
6040   }
6041
6042   if ( elemIt && elemIt->more() && !typeOK )
6043   {
6044     if ( elemType == SMDSAbs_Node )
6045     {
6046       elemIt = SMDS_ElemIteratorPtr( new NodeOfElemIterator( elemIt ));
6047     }
6048     else
6049     {
6050       elemIt = SMDS_ElemIteratorPtr();
6051     }
6052   }
6053   return elemIt;
6054 }
6055
6056 //=============================================================================
6057 namespace // Finding concurrent hypotheses
6058 //=============================================================================
6059 {
6060
6061 /*!
6062  * \brief mapping of mesh dimension into shape type
6063  */
6064 TopAbs_ShapeEnum shapeTypeByDim(const int theDim)
6065 {
6066   TopAbs_ShapeEnum aType = TopAbs_SOLID;
6067   switch ( theDim ) {
6068   case 0: aType = TopAbs_VERTEX; break;
6069   case 1: aType = TopAbs_EDGE; break;
6070   case 2: aType = TopAbs_FACE; break;
6071   case 3:
6072   default:aType = TopAbs_SOLID; break;
6073   }
6074   return aType;
6075 }
6076
6077 //-----------------------------------------------------------------------------
6078 /*!
6079  * \brief Internal structure used to find concurrent submeshes
6080  *
6081  * It represents a pair < submesh, concurrent dimension >, where
6082  * 'concurrent dimension' is dimension of shape where the submesh can concurrent
6083  *  with another submesh. In other words, it is dimension of a hypothesis assigned
6084  *  to submesh.
6085  */
6086 class SMESH_DimHyp
6087 {
6088  public:
6089   //! fields
6090   int _dim;    //!< a dimension the algo can build (concurrent dimension)
6091   int _ownDim; //!< dimension of shape of _subMesh (>=_dim)
6092   TopTools_MapOfShape _shapeMap;
6093   SMESH_subMesh*      _subMesh;
6094   list<const SMESHDS_Hypothesis*> _hypotheses; //!< algo is first, then its parameters
6095
6096   //-----------------------------------------------------------------------------
6097   // Return the algorithm
6098   const SMESH_Algo* GetAlgo() const
6099   { return _hypotheses.empty() ? 0 : dynamic_cast<const SMESH_Algo*>( _hypotheses.front() ); }
6100
6101   //-----------------------------------------------------------------------------
6102   //! Constructors
6103   SMESH_DimHyp(const SMESH_subMesh* theSubMesh,
6104                const int            theDim,
6105                const TopoDS_Shape&  theShape)
6106   {
6107     _subMesh = (SMESH_subMesh*)theSubMesh;
6108     SetShape( theDim, theShape );
6109   }
6110
6111   //-----------------------------------------------------------------------------
6112   //! set shape
6113   void SetShape(const int           theDim,
6114                 const TopoDS_Shape& theShape)
6115   {
6116     _dim = theDim;
6117     _ownDim = SMESH_Gen::GetShapeDim(theShape);
6118     if (_dim >= _ownDim)
6119       _shapeMap.Add( theShape );
6120     else {
6121       TopExp_Explorer anExp( theShape, shapeTypeByDim(theDim) );
6122       for( ; anExp.More(); anExp.Next() )
6123         _shapeMap.Add( anExp.Current() );
6124     }
6125   }
6126
6127   //-----------------------------------------------------------------------------
6128   //! Check sharing of sub-shapes
6129   static bool isShareSubShapes(const TopTools_MapOfShape& theToCheck,
6130                                const TopTools_MapOfShape& theToFind,
6131                                const TopAbs_ShapeEnum     theType)
6132   {
6133     bool isShared = false;
6134     TopTools_MapIteratorOfMapOfShape anItr( theToCheck );
6135     for (; !isShared && anItr.More(); anItr.Next() )
6136     {
6137       const TopoDS_Shape aSubSh = anItr.Key();
6138       // check for case when concurrent dimensions are same
6139       isShared = theToFind.Contains( aSubSh );
6140       // check for sub-shape with concurrent dimension
6141       TopExp_Explorer anExp( aSubSh, theType );
6142       for ( ; !isShared && anExp.More(); anExp.Next() )
6143         isShared = theToFind.Contains( anExp.Current() );
6144     }
6145     return isShared;
6146   }
6147
6148   //-----------------------------------------------------------------------------
6149   //! check algorithms
6150   static bool checkAlgo(const SMESHDS_Hypothesis* theA1,
6151                         const SMESHDS_Hypothesis* theA2)
6152   {
6153     if ( !theA1 || !theA2 ||
6154          theA1->GetType() == SMESHDS_Hypothesis::PARAM_ALGO ||
6155          theA2->GetType() == SMESHDS_Hypothesis::PARAM_ALGO )
6156       return false; // one of the hypothesis is not algorithm
6157     // check algorithm names (should be equal)
6158     return strcmp( theA1->GetName(), theA2->GetName() ) == 0;
6159   }
6160
6161
6162   //-----------------------------------------------------------------------------
6163   //! Check if sub-shape hypotheses are concurrent
6164   bool IsConcurrent(const SMESH_DimHyp* theOther) const
6165   {
6166     if ( _subMesh == theOther->_subMesh )
6167       return false; // same sub-shape - should not be
6168
6169     // if ( <own dim of either of submeshes> == <concurrent dim> &&
6170     //      any of the two submeshes is not on COMPOUND shape )
6171     //  -> no concurrency
6172     bool meIsCompound    = (_subMesh->GetSubMeshDS() &&
6173                             _subMesh->GetSubMeshDS()->IsComplexSubmesh());
6174     bool otherIsCompound = (theOther->_subMesh->GetSubMeshDS() &&
6175                             theOther->_subMesh->GetSubMeshDS()->IsComplexSubmesh());
6176     if ( (_ownDim == _dim  || theOther->_ownDim == _dim ) && (!meIsCompound || !otherIsCompound))
6177       return false;
6178
6179     bool checkSubShape = isShareSubShapes( _shapeMap, theOther->_shapeMap, shapeTypeByDim(_dim));
6180     if ( !checkSubShape )
6181       return false;
6182
6183     // check algorithms to be same
6184     const SMESH_Algo* a1 = this->GetAlgo();
6185     const SMESH_Algo* a2 = theOther->GetAlgo();
6186     bool isSame = checkAlgo( a1, a2 );
6187     if ( !isSame )
6188     {
6189       if ( !a1 || !a2 )
6190         return false; // pb?
6191       return a1->GetDim() == a2->GetDim(); // different algorithms of same dim -> concurrency !
6192     }
6193
6194     // check hypothesises for concurrence (skip first as algorithm)
6195     size_t nbSame = 0;
6196     // pointers should be same, because it is referened from mesh hypothesis partition
6197     list <const SMESHDS_Hypothesis*>::const_iterator hypIt = _hypotheses.begin();
6198     list <const SMESHDS_Hypothesis*>::const_iterator otheEndIt = theOther->_hypotheses.end();
6199     for ( hypIt++ /*skip first as algo*/; hypIt != _hypotheses.end(); hypIt++ )
6200       if ( find( theOther->_hypotheses.begin(), otheEndIt, *hypIt ) != otheEndIt )
6201         nbSame++;
6202     // the submeshes are concurrent if their algorithms has different parameters
6203     return nbSame != theOther->_hypotheses.size() - 1;
6204   }
6205
6206   // Return true if algorithm of this SMESH_DimHyp is used if no
6207   // sub-mesh order is imposed by the user
6208   bool IsHigherPriorityThan( const SMESH_DimHyp* theOther ) const
6209   {
6210     // NeedDiscreteBoundary() algo has a higher priority
6211     if ( this    ->GetAlgo()->NeedDiscreteBoundary() !=
6212          theOther->GetAlgo()->NeedDiscreteBoundary() )
6213       return !this->GetAlgo()->NeedDiscreteBoundary();
6214
6215     return ( this->_subMesh->GetId() < theOther->_subMesh->GetId() );
6216   }
6217
6218 }; // end of SMESH_DimHyp
6219 //-----------------------------------------------------------------------------
6220
6221 typedef list<const SMESH_DimHyp*> TDimHypList;
6222
6223 //-----------------------------------------------------------------------------
6224
6225 void addDimHypInstance(const int                               theDim,
6226                        const TopoDS_Shape&                     theShape,
6227                        const SMESH_Algo*                       theAlgo,
6228                        const SMESH_subMesh*                    theSubMesh,
6229                        const list <const SMESHDS_Hypothesis*>& theHypList,
6230                        TDimHypList*                            theDimHypListArr )
6231 {
6232   TDimHypList& listOfdimHyp = theDimHypListArr[theDim];
6233   if ( listOfdimHyp.empty() || listOfdimHyp.back()->_subMesh != theSubMesh ) {
6234     SMESH_DimHyp* dimHyp = new SMESH_DimHyp( theSubMesh, theDim, theShape );
6235     dimHyp->_hypotheses.push_front(theAlgo);
6236     listOfdimHyp.push_back( dimHyp );
6237   }
6238
6239   SMESH_DimHyp* dimHyp = const_cast<SMESH_DimHyp*>( listOfdimHyp.back() );
6240   dimHyp->_hypotheses.insert( dimHyp->_hypotheses.end(),
6241                               theHypList.begin(), theHypList.end() );
6242 }
6243
6244 //-----------------------------------------------------------------------------
6245 void addInOrderOfPriority( const SMESH_DimHyp* theDimHyp,
6246                            TDimHypList&        theListOfConcurr)
6247 {
6248   if ( theListOfConcurr.empty() )
6249   {
6250     theListOfConcurr.push_back( theDimHyp );
6251   }
6252   else
6253   {
6254     TDimHypList::iterator hypIt = theListOfConcurr.begin();
6255     while ( hypIt != theListOfConcurr.end() &&
6256             !theDimHyp->IsHigherPriorityThan( *hypIt ))
6257       ++hypIt;
6258     theListOfConcurr.insert( hypIt, theDimHyp );
6259   }
6260 }
6261
6262 //-----------------------------------------------------------------------------
6263 void findConcurrents(const SMESH_DimHyp* theDimHyp,
6264                      const TDimHypList&  theListOfDimHyp,
6265                      TDimHypList&        theListOfConcurrHyp,
6266                      set<int>&           theSetOfConcurrId )
6267 {
6268   TDimHypList::const_reverse_iterator rIt = theListOfDimHyp.rbegin();
6269   for ( ; rIt != theListOfDimHyp.rend(); rIt++ )
6270   {
6271     const SMESH_DimHyp* curDimHyp = *rIt;
6272     if ( curDimHyp == theDimHyp )
6273       break; // meet own dimHyp pointer in same dimension
6274
6275     if ( theDimHyp->IsConcurrent( curDimHyp ) &&
6276          theSetOfConcurrId.insert( curDimHyp->_subMesh->GetId() ).second )
6277     {
6278       addInOrderOfPriority( curDimHyp, theListOfConcurrHyp );
6279     }
6280   }
6281 }
6282
6283 //-----------------------------------------------------------------------------
6284 void unionLists(TListOfInt&       theListOfId,
6285                 TListOfListOfInt& theListOfListOfId,
6286                 const int         theIndx )
6287 {
6288   TListOfListOfInt::iterator it = theListOfListOfId.begin();
6289   for ( int i = 0; it != theListOfListOfId.end(); it++, i++ ) {
6290     if ( i < theIndx )
6291       continue; //skip already treated lists
6292     // check if other list has any same submesh object
6293     TListOfInt& otherListOfId = *it;
6294     if ( find_first_of( theListOfId.begin(), theListOfId.end(),
6295                         otherListOfId.begin(), otherListOfId.end() ) == theListOfId.end() )
6296       continue;
6297
6298     // union two lists (from source into target)
6299     TListOfInt::iterator it2 = otherListOfId.begin();
6300     for ( ; it2 != otherListOfId.end(); it2++ ) {
6301       if ( find( theListOfId.begin(), theListOfId.end(), (*it2) ) == theListOfId.end() )
6302         theListOfId.push_back(*it2);
6303     }
6304     // clear source list
6305     otherListOfId.clear();
6306   }
6307 }
6308 //-----------------------------------------------------------------------------
6309
6310 //! free memory allocated for dimension-hypothesis objects
6311 void removeDimHyps( TDimHypList* theArrOfList )
6312 {
6313   for (int i = 0; i < 4; i++ ) {
6314     TDimHypList& listOfdimHyp = theArrOfList[i];
6315     TDimHypList::const_iterator it = listOfdimHyp.begin();
6316     for ( ; it != listOfdimHyp.end(); it++ )
6317       delete (*it);
6318   }
6319 }
6320
6321 //-----------------------------------------------------------------------------
6322 /*!
6323  * \brief find common submeshes with given submesh
6324  * \param theSubMeshList list of already collected submesh to check
6325  * \param theSubMesh given submesh to intersect with other
6326  * \param theCommonSubMeshes collected common submeshes
6327  */
6328 void findCommonSubMesh (list<const SMESH_subMesh*>& theSubMeshList,
6329                         const SMESH_subMesh*        theSubMesh,
6330                         set<const SMESH_subMesh*>&  theCommon )
6331 {
6332   if ( !theSubMesh )
6333     return;
6334   list<const SMESH_subMesh*>::const_iterator it = theSubMeshList.begin();
6335   for ( ; it != theSubMeshList.end(); it++ )
6336     theSubMesh->FindIntersection( *it, theCommon );
6337   theSubMeshList.push_back( theSubMesh );
6338   //theCommon.insert( theSubMesh );
6339 }
6340
6341 //-----------------------------------------------------------------------------
6342 bool isSubMeshInList ( int smID, const TListOfListOfInt& smLists )
6343 {
6344   TListOfListOfInt::const_iterator listsIt = smLists.begin();
6345   for ( ; listsIt != smLists.end(); ++listsIt )
6346   {
6347     const TListOfInt& smIDs = *listsIt;
6348     if ( std::find( smIDs.begin(), smIDs.end(), smID ) != smIDs.end() )
6349       return true;
6350   }
6351   return false;
6352 }
6353
6354 } // namespace
6355
6356 //=============================================================================
6357 /*!
6358  * \brief Return \c true if a meshing order not yet set for a concurrent sub-mesh
6359  */
6360 //=============================================================================
6361
6362 CORBA::Boolean SMESH_Mesh_i::IsUnorderedSubMesh(CORBA::Long submeshID)
6363 {
6364   TListOfListOfInt anOrder = GetImpl().GetMeshOrder(); // already defined order
6365   if ( isSubMeshInList( submeshID, anOrder ))
6366     return false;
6367
6368   TListOfListOfInt allConurrent = findConcurrentSubMeshes();
6369   return isSubMeshInList( submeshID, allConurrent );
6370 }
6371
6372 //=============================================================================
6373 /*!
6374  * \brief Return submesh objects list in meshing order
6375  */
6376 //=============================================================================
6377
6378 SMESH::submesh_array_array* SMESH_Mesh_i::GetMeshOrder()
6379 {
6380   SMESH::submesh_array_array_var aResult = new SMESH::submesh_array_array();
6381
6382   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
6383   if ( !aMeshDS )
6384     return aResult._retn();
6385
6386   TListOfListOfInt      anOrder = GetImpl().GetMeshOrder(); // already defined order
6387   TListOfListOfInt allConurrent = findConcurrentSubMeshes();
6388   anOrder.splice( anOrder.end(), allConurrent );
6389
6390   int listIndx = 0;
6391   TListOfListOfInt::iterator listIt = anOrder.begin();
6392   for(; listIt != anOrder.end(); listIt++, listIndx++ )
6393     unionLists( *listIt,  anOrder, listIndx + 1 );
6394
6395   // convert submesh ids into interface instances
6396   //  and dump command into python
6397   convertMeshOrder( anOrder, aResult, false );
6398
6399   return aResult._retn();
6400 }
6401
6402 //=============================================================================
6403 /*!
6404  * \brief Finds concurrent sub-meshes
6405  */
6406 //=============================================================================
6407
6408 TListOfListOfInt SMESH_Mesh_i::findConcurrentSubMeshes()
6409 {
6410   TListOfListOfInt anOrder;
6411   ::SMESH_Mesh& mesh = GetImpl();
6412   {
6413     // collect submeshes and detect concurrent algorithms and hypothesises
6414     TDimHypList dimHypListArr[4]; // dimHyp list for each shape dimension
6415
6416     map<int, ::SMESH_subMesh*>::iterator i_sm = _mapSubMesh.begin();
6417     for ( ; i_sm != _mapSubMesh.end(); i_sm++ ) {
6418       ::SMESH_subMesh* sm = (*i_sm).second;
6419       // shape of submesh
6420       const TopoDS_Shape& aSubMeshShape = sm->GetSubShape();
6421
6422       // list of assigned hypothesises
6423       const list <const SMESHDS_Hypothesis*>& hypList = mesh.GetHypothesisList(aSubMeshShape);
6424       // Find out dimensions where the submesh can be concurrent.
6425       // We define the dimensions by algo of each of hypotheses in hypList
6426       list <const SMESHDS_Hypothesis*>::const_iterator hypIt = hypList.begin();
6427       for( ; hypIt != hypList.end(); hypIt++ ) {
6428         SMESH_Algo* anAlgo = 0;
6429         const SMESH_Hypothesis* hyp = dynamic_cast<const SMESH_Hypothesis*>(*hypIt);
6430         if ( hyp->GetType() != SMESHDS_Hypothesis::PARAM_ALGO )
6431           // hyp it-self is algo
6432           anAlgo = (SMESH_Algo*)dynamic_cast<const SMESH_Algo*>(hyp);
6433         else {
6434           // try to find algorithm with help of sub-shapes
6435           TopExp_Explorer anExp( aSubMeshShape, shapeTypeByDim(hyp->GetDim()) );
6436           for ( ; !anAlgo && anExp.More(); anExp.Next() )
6437             anAlgo = mesh.GetGen()->GetAlgo( mesh, anExp.Current() );
6438         }
6439         if (!anAlgo)
6440           continue; // no algorithm assigned to a current submesh
6441
6442         int dim = anAlgo->GetDim(); // top concurrent dimension (see comment to SMESH_DimHyp)
6443         // the submesh can concurrent at <dim> (or lower dims if !anAlgo->NeedDiscreteBoundary())
6444
6445         // create instance of dimension-hypothesis for found concurrent dimension(s) and algorithm
6446         for ( int j = anAlgo->NeedDiscreteBoundary() ? dim : 1, jn = dim; j <= jn; j++ )
6447           addDimHypInstance( j, aSubMeshShape, anAlgo, sm, hypList, dimHypListArr );
6448       }
6449     } // end iterations on submesh
6450
6451     // iterate on created dimension-hypotheses and check for concurrents
6452     for ( int i = 0; i < 4; i++ ) {
6453       const TDimHypList& listOfDimHyp = dimHypListArr[i];
6454       // check for concurrents in own and other dimensions (step-by-step)
6455       TDimHypList::const_iterator dhIt = listOfDimHyp.begin();
6456       for ( ; dhIt != listOfDimHyp.end(); dhIt++ ) {
6457         const SMESH_DimHyp* dimHyp = *dhIt;
6458         TDimHypList listOfConcurr;
6459         set<int>    setOfConcurrIds;
6460         // looking for concurrents and collect into own list
6461         for ( int j = i; j < 4; j++ )
6462           findConcurrents( dimHyp, dimHypListArr[j], listOfConcurr, setOfConcurrIds );
6463         // check if any concurrents found
6464         if ( listOfConcurr.size() > 0 ) {
6465           // add own submesh to list of concurrent
6466           addInOrderOfPriority( dimHyp, listOfConcurr );
6467           list<int> listOfConcurrIds;
6468           TDimHypList::iterator hypIt = listOfConcurr.begin();
6469           for ( ; hypIt != listOfConcurr.end(); ++hypIt )
6470             listOfConcurrIds.push_back( (*hypIt)->_subMesh->GetId() );
6471           anOrder.push_back( listOfConcurrIds );
6472         }
6473       }
6474     }
6475
6476     removeDimHyps(dimHypListArr);
6477
6478     // now, minimize the number of concurrent groups
6479     // Here we assume that lists of submeshes can have same submesh
6480     // in case of multi-dimension algorithms, as result
6481     //  list with common submesh has to be united into one list
6482     int listIndx = 0;
6483     TListOfListOfInt::iterator listIt = anOrder.begin();
6484     for(; listIt != anOrder.end(); listIt++, listIndx++ )
6485       unionLists( *listIt,  anOrder, listIndx + 1 );
6486   }
6487
6488   return anOrder;
6489 }
6490
6491 //=============================================================================
6492 /*!
6493  * \brief Set submesh object order
6494  * \param theSubMeshArray submesh array order
6495  */
6496 //=============================================================================
6497
6498 ::CORBA::Boolean SMESH_Mesh_i::SetMeshOrder(const SMESH::submesh_array_array& theSubMeshArray)
6499 {
6500   if ( _preMeshInfo )
6501     _preMeshInfo->ForgetOrLoad();
6502
6503   bool res = false;
6504   ::SMESH_Mesh& mesh = GetImpl();
6505
6506   TPythonDump aPythonDump; // prevent dump of called methods
6507   aPythonDump << "isDone = " << SMESH::SMESH_Mesh_var(_this()) << ".SetMeshOrder( [ ";
6508
6509   TListOfListOfInt subMeshOrder;
6510   for ( int i = 0, n = theSubMeshArray.length(); i < n; i++ )
6511   {
6512     const SMESH::submesh_array& aSMArray = theSubMeshArray[i];
6513     TListOfInt subMeshIds;
6514     if ( i > 0 )
6515       aPythonDump << ", ";
6516     aPythonDump << "[ ";
6517     // Collect subMeshes which should be clear
6518     //  do it list-by-list, because modification of submesh order
6519     //  take effect between concurrent submeshes only
6520     set<const SMESH_subMesh*> subMeshToClear;
6521     list<const SMESH_subMesh*> subMeshList;
6522     for ( int j = 0, jn = aSMArray.length(); j < jn; j++ )
6523     {
6524       const SMESH::SMESH_subMesh_var subMesh = SMESH::SMESH_subMesh::_duplicate(aSMArray[j]);
6525       if ( j > 0 )
6526         aPythonDump << ", ";
6527       aPythonDump << subMesh;
6528       subMeshIds.push_back( subMesh->GetId() );
6529       // detect common parts of submeshes
6530       if ( _mapSubMesh.find(subMesh->GetId()) != _mapSubMesh.end() )
6531         findCommonSubMesh( subMeshList, _mapSubMesh[ subMesh->GetId() ], subMeshToClear );
6532     }
6533     aPythonDump << " ]";
6534     subMeshOrder.push_back( subMeshIds );
6535
6536     // clear collected sub-meshes
6537     set<const SMESH_subMesh*>::iterator clrIt = subMeshToClear.begin();
6538     for ( ; clrIt != subMeshToClear.end(); clrIt++ )
6539       if ( SMESH_subMesh* sm = (SMESH_subMesh*)*clrIt )
6540       {
6541         sm->ComputeStateEngine( SMESH_subMesh::CLEAN );
6542         if ( SMESH_Algo* algo = sm->GetAlgo() ) // #16748
6543           sm->AlgoStateEngine( SMESH_subMesh::MODIF_HYP, algo ); // to clear a cached algo
6544       }
6545   }
6546   aPythonDump << " ])";
6547
6548   mesh.SetMeshOrder( subMeshOrder );
6549   res = true;
6550
6551   SMESH::SMESH_Mesh_var me = _this();
6552   _gen_i->UpdateIcons( me );
6553
6554   return res;
6555 }
6556
6557 //=============================================================================
6558 /*!
6559  * \brief Convert submesh ids into submesh interfaces
6560  */
6561 //=============================================================================
6562
6563 void SMESH_Mesh_i::convertMeshOrder (const TListOfListOfInt&     theIdsOrder,
6564                                      SMESH::submesh_array_array& theResOrder,
6565                                      const bool                  theIsDump)
6566 {
6567   int nbSet = theIdsOrder.size();
6568   TPythonDump aPythonDump; // prevent dump of called methods
6569   if ( theIsDump )
6570     aPythonDump << "[ ";
6571   theResOrder.length(nbSet);
6572   TListOfListOfInt::const_iterator it = theIdsOrder.begin();
6573   int listIndx = 0;
6574   for( ; it != theIdsOrder.end(); it++ ) {
6575     // translate submesh identificators into submesh objects
6576     //  takeing into account real number of concurrent lists
6577     const TListOfInt& aSubOrder = (*it);
6578     if (!aSubOrder.size())
6579       continue;
6580     if ( theIsDump )
6581       aPythonDump << "[ ";
6582     // convert shape indices into interfaces
6583     SMESH::submesh_array_var aResSubSet = new SMESH::submesh_array();
6584     aResSubSet->length(aSubOrder.size());
6585     TListOfInt::const_iterator subIt = aSubOrder.begin();
6586     int j;
6587     for( j = 0; subIt != aSubOrder.end(); subIt++ ) {
6588       if ( _mapSubMeshIor.find(*subIt) == _mapSubMeshIor.end() )
6589         continue;
6590       SMESH::SMESH_subMesh_var subMesh =
6591         SMESH::SMESH_subMesh::_duplicate( _mapSubMeshIor[*subIt] );
6592       if ( theIsDump ) {
6593         if ( j > 0 )
6594           aPythonDump << ", ";
6595         aPythonDump << subMesh;
6596       }
6597       aResSubSet[ j++ ] = subMesh;
6598     }
6599     if ( theIsDump )
6600       aPythonDump << " ]";
6601     if ( j > 1 )
6602       theResOrder[ listIndx++ ] = aResSubSet;
6603   }
6604   // correct number of lists
6605   theResOrder.length( listIndx );
6606
6607   if ( theIsDump ) {
6608     // finilise python dump
6609     aPythonDump << " ]";
6610     aPythonDump << " = " << SMESH::SMESH_Mesh_var(_this()) << ".GetMeshOrder()";
6611   }
6612 }
6613
6614 namespace // utils used by SMESH_MeshPartDS
6615 {
6616   /*!
6617    * \brief Class used to access to protected data of SMDS_MeshInfo
6618    */
6619   struct TMeshInfo : public SMDS_MeshInfo
6620   {
6621     void Add(const SMDS_MeshElement* e) { SMDS_MeshInfo::addWithPoly( e ); }
6622   };
6623   /*!
6624    * \brief Element holing its ID only
6625    */
6626   struct TElemID : public SMDS_LinearEdge
6627   {
6628     TElemID(int ID) : SMDS_LinearEdge(0,0) { setID( ID ); }
6629   };
6630 }
6631
6632 //================================================================================
6633 //
6634 // Implementation of SMESH_MeshPartDS
6635 //
6636 SMESH_MeshPartDS::SMESH_MeshPartDS(SMESH::SMESH_IDSource_ptr meshPart):
6637   SMESHDS_Mesh( /*meshID=*/-1, /*isEmbeddedMode=*/true)
6638 {
6639   SMESH::SMESH_Mesh_var mesh = meshPart->GetMesh();
6640   SMESH_Mesh_i*       mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
6641
6642   mesh_i->Load();
6643   _meshDS = mesh_i->GetImpl().GetMeshDS();
6644
6645   SetPersistentId( _meshDS->GetPersistentId() );
6646
6647   if ( mesh_i == SMESH::DownCast<SMESH_Mesh_i*>( meshPart ))
6648   {
6649     // <meshPart> is the whole mesh
6650     myInfo = _meshDS->GetMeshInfo(); // copy mesh info;
6651     // copy groups
6652     set<SMESHDS_GroupBase*>& myGroupSet = const_cast<set<SMESHDS_GroupBase*>&>( GetGroups() );
6653     myGroupSet = _meshDS->GetGroups();
6654   }
6655   else
6656   {
6657     TMeshInfo tmpInfo;
6658     SMESH::long_array_var           anIDs = meshPart->GetIDs();
6659     SMESH::array_of_ElementType_var types = meshPart->GetTypes();
6660     if ( types->length() == 1 && types[0] == SMESH::NODE ) // group of nodes
6661     {
6662       for ( CORBA::ULong i=0; i < anIDs->length(); i++ )
6663         if ( const SMDS_MeshNode * n = _meshDS->FindNode( anIDs[i] ))
6664           if ( _elements[ SMDSAbs_Node ].insert( n ).second )
6665             tmpInfo.Add( n );
6666     }
6667     else
6668     {
6669       for ( CORBA::ULong i=0; i < anIDs->length(); i++ )
6670         if ( const SMDS_MeshElement * e = _meshDS->FindElement(anIDs[i]))
6671           if ( _elements[ e->GetType() ].insert( e ).second )
6672           {
6673             tmpInfo.Add( e );
6674             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
6675             while ( nIt->more() )
6676             {
6677               const SMDS_MeshNode * n = (const SMDS_MeshNode*) nIt->next();
6678               if ( _elements[ SMDSAbs_Node ].insert( n ).second )
6679                 tmpInfo.Add( n );
6680             }
6681           }
6682     }
6683     myInfo = tmpInfo;
6684
6685     ShapeToMesh( _meshDS->ShapeToMesh() );
6686
6687     _meshDS = 0; // to enforce iteration on _elements and _nodes
6688   }
6689 }
6690 // -------------------------------------------------------------------------------------
6691 SMESH_MeshPartDS::SMESH_MeshPartDS(const std::list< const SMDS_MeshElement* > & meshPart):
6692   SMESHDS_Mesh( /*meshID=*/-1, /*isEmbeddedMode=*/true), _meshDS(0)
6693 {
6694   TMeshInfo tmpInfo;
6695   list< const SMDS_MeshElement* >::const_iterator partIt = meshPart.begin();
6696   for ( ; partIt != meshPart.end(); ++partIt )
6697     if ( const SMDS_MeshElement * e = *partIt )
6698       if ( _elements[ e->GetType() ].insert( e ).second )
6699       {
6700         tmpInfo.Add( e );
6701         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
6702         while ( nIt->more() )
6703         {
6704           const SMDS_MeshNode * n = (const SMDS_MeshNode*) nIt->next();
6705           if ( _elements[ SMDSAbs_Node ].insert( n ).second )
6706             tmpInfo.Add( n );
6707         }
6708       }
6709   myInfo = tmpInfo;
6710 }
6711 // -------------------------------------------------------------------------------------
6712 const SMDS_MeshElement * SMESH_MeshPartDS::FindElement(int IDelem) const
6713 {
6714   if ( _meshDS ) return _meshDS->FindElement( IDelem );
6715
6716   TElemID elem( IDelem );
6717   for ( int iType = SMDSAbs_Edge; iType < SMDSAbs_NbElementTypes; ++iType )
6718     if ( !_elements[ iType ].empty() )
6719     {
6720       TIDSortedElemSet::const_iterator it = _elements[ iType ].find( &elem );
6721       if ( it != _elements[ iType ].end() )
6722         return *it;
6723     }
6724   return 0;
6725 }
6726 // -------------------------------------------------------------------------------------
6727 bool SMESH_MeshPartDS::HasNumerationHoles()
6728 {
6729   if ( _meshDS ) return _meshDS->HasNumerationHoles();
6730
6731   return ( MinNodeID() != 1 ||
6732            MaxNodeID() != NbNodes() ||
6733            MinElementID() != 1 ||
6734            MaxElementID() != NbElements() );
6735 }
6736 // -------------------------------------------------------------------------------------
6737 int SMESH_MeshPartDS::MaxNodeID() const
6738 {
6739   if ( _meshDS ) return _meshDS->MaxNodeID();
6740   return NbNodes() == 0 ? 0 : (*_elements[ SMDSAbs_Node ].rbegin())->GetID();
6741 }
6742 // -------------------------------------------------------------------------------------
6743 int SMESH_MeshPartDS::MinNodeID() const
6744 {
6745   if ( _meshDS ) return _meshDS->MinNodeID();
6746   return NbNodes() == 0 ? 0 : (*_elements[ SMDSAbs_Node ].begin())->GetID();
6747 }  
6748 // -------------------------------------------------------------------------------------
6749 int SMESH_MeshPartDS::MaxElementID() const
6750 {
6751   if ( _meshDS ) return _meshDS->MaxElementID();
6752   int maxID = 0;
6753   for ( int iType = SMDSAbs_Edge; iType < SMDSAbs_NbElementTypes; ++iType )
6754     if ( !_elements[ iType ].empty() )
6755       maxID = Max( maxID, (*_elements[ iType ].rbegin())->GetID() );
6756   return maxID;
6757 }
6758 // -------------------------------------------------------------------------------------
6759 int SMESH_MeshPartDS::MinElementID() const
6760 {
6761   if ( _meshDS ) return _meshDS->MinElementID();
6762   int minID = 0;
6763   for ( int iType = SMDSAbs_Edge; iType < SMDSAbs_NbElementTypes; ++iType )
6764     if ( !_elements[ iType ].empty() )
6765       minID = Min( minID, (*_elements[ iType ].begin())->GetID() );
6766   return minID;
6767 }
6768 // -------------------------------------------------------------------------------------
6769 SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementGeomIterator(SMDSAbs_GeometryType geomType) const
6770 {
6771   if ( _meshDS ) return _meshDS->elementGeomIterator( geomType );
6772
6773   typedef SMDS_SetIterator
6774     <const SMDS_MeshElement*,
6775     TIDSortedElemSet::const_iterator,
6776     SMDS::SimpleAccessor<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator>,
6777     SMDS_MeshElement::GeomFilter
6778     > TIter;
6779
6780   SMDSAbs_ElementType type = SMDS_MeshCell::ElemType( geomType );
6781
6782   return SMDS_ElemIteratorPtr( new TIter( _elements[type].begin(),
6783                                           _elements[type].end(),
6784                                           SMDS_MeshElement::GeomFilter( geomType )));
6785 }
6786 // -------------------------------------------------------------------------------------
6787 SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementEntityIterator(SMDSAbs_EntityType entity) const
6788 {
6789   if ( _meshDS ) return _meshDS->elementEntityIterator( entity );
6790
6791   typedef SMDS_SetIterator
6792     <const SMDS_MeshElement*,
6793     TIDSortedElemSet::const_iterator,
6794     SMDS::SimpleAccessor<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator>,
6795     SMDS_MeshElement::EntityFilter
6796     > TIter;
6797
6798   SMDSAbs_ElementType type = SMDS_MeshCell::ElemType( entity );
6799
6800   return SMDS_ElemIteratorPtr( new TIter( _elements[type].begin(),
6801                                           _elements[type].end(),
6802                                           SMDS_MeshElement::EntityFilter( entity )));
6803 }
6804 // -------------------------------------------------------------------------------------
6805 SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementsIterator(SMDSAbs_ElementType type) const
6806 {
6807   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator > TIter;
6808   if ( type == SMDSAbs_All && !_meshDS )
6809   {
6810     typedef vector< SMDS_ElemIteratorPtr > TIterVec;
6811     TIterVec iterVec;
6812     for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
6813       if ( !_elements[i].empty() && i != SMDSAbs_Node )
6814         iterVec.push_back
6815           ( SMDS_ElemIteratorPtr( new TIter( _elements[i].begin(), _elements[i].end() )));
6816
6817     typedef SMDS_IteratorOnIterators<const SMDS_MeshElement*, TIterVec > TIterOnIters;
6818     return SMDS_ElemIteratorPtr( new TIterOnIters( iterVec ));
6819   }
6820   return _meshDS ? _meshDS->elementsIterator(type) : SMDS_ElemIteratorPtr
6821       ( new TIter( _elements[type].begin(), _elements[type].end() ));
6822 }
6823 // -------------------------------------------------------------------------------------
6824 #define _GET_ITER_DEFINE( iterType, methName, elem, elemType)                       \
6825   iterType SMESH_MeshPartDS::methName() const                 \
6826   {                                                                                 \
6827     typedef SMDS_SetIterator<const elem*, TIDSortedElemSet::const_iterator > TIter; \
6828     return _meshDS ? _meshDS->methName() : iterType                 \
6829       ( new TIter( _elements[elemType].begin(), _elements[elemType].end() ));       \
6830   }
6831 // -------------------------------------------------------------------------------------
6832 _GET_ITER_DEFINE( SMDS_NodeIteratorPtr, nodesIterator, SMDS_MeshNode, SMDSAbs_Node )
6833 _GET_ITER_DEFINE( SMDS_EdgeIteratorPtr, edgesIterator, SMDS_MeshEdge, SMDSAbs_Edge )
6834 _GET_ITER_DEFINE( SMDS_FaceIteratorPtr, facesIterator, SMDS_MeshFace, SMDSAbs_Face )
6835 _GET_ITER_DEFINE( SMDS_VolumeIteratorPtr, volumesIterator, SMDS_MeshVolume, SMDSAbs_Volume)
6836 #undef _GET_ITER_DEFINE
6837 //
6838 // END Implementation of SMESH_MeshPartDS
6839 //
6840 //================================================================================