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