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