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