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