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