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