Salome HOME
+ SMDS_Mesh::CheckMemory(); // PAL16631
[modules/smesh.git] / src / OBJECT / SMESH_Object.cxx
1 //  SMESH OBJECT : interactive object for SMESH visualization
2 //
3 //  Copyright (C) 2003  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. 
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 //
23 //
24 //  File   : SMESH_Grid.cxx
25 //  Author : Nicolas REJNERI
26 //  Module : SMESH
27
28 #include "SMESH_ObjectDef.h"
29 #include "SMESH_ActorUtils.h"
30
31 #include "SMDS_Mesh.hxx"
32 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
33 #include "SMESH_Actor.h"
34 #include "SMESH_ControlsDef.hxx"
35 #include "SalomeApp_Application.h"
36 #include "VTKViewer_ExtractUnstructuredGrid.h"
37 #include "VTKViewer_CellLocationsArray.h"
38
39 #include CORBA_SERVER_HEADER(SMESH_Gen)
40 #include CORBA_SERVER_HEADER(SALOME_Exception)
41
42 #include <vtkCell.h>
43 #include <vtkIdList.h>
44 #include <vtkCellArray.h>
45 #include <vtkUnsignedCharArray.h>
46
47 #include <vtkUnstructuredGrid.h>
48
49 #include <memory>
50 #include <sstream>      
51 #include <stdexcept>
52 #include <set>
53
54 #include "utilities.h"
55
56 using namespace std;
57
58 #ifndef EXCEPTION
59 #define EXCEPTION(TYPE, MSG) {\
60   std::ostringstream aStream;\
61   aStream<<__FILE__<<"["<<__LINE__<<"]::"<<MSG;\
62   throw TYPE(aStream.str());\
63 }
64 #endif
65
66 #ifdef _DEBUG_
67 static int MYDEBUG = 0;
68 static int MYDEBUGWITHFILES = 0;
69 #else
70 static int MYDEBUG = 0;
71 static int MYDEBUGWITHFILES = 0;
72 #endif
73
74
75 /*
76   Class       : SMESH_VisualObjDef
77   Description : Base class for all mesh objects to be visuilised
78 */
79
80 //=================================================================================
81 // function : getCellType
82 // purpose  : Get type of VTK cell
83 //=================================================================================
84 static inline vtkIdType getCellType( const SMDSAbs_ElementType theType,
85                                      const bool thePoly,
86                                      const int theNbNodes )
87 {
88   switch( theType )
89   {
90     case SMDSAbs_Edge: 
91       if( theNbNodes == 2 )         return VTK_LINE;
92       else if ( theNbNodes == 3 )   return VTK_QUADRATIC_EDGE;
93       else return VTK_EMPTY_CELL;
94
95     case SMDSAbs_Face  :
96       if (thePoly && theNbNodes>2 ) return VTK_POLYGON;
97       else if ( theNbNodes == 3 )   return VTK_TRIANGLE;
98       else if ( theNbNodes == 4 )   return VTK_QUAD;
99       else if ( theNbNodes == 6 )   return VTK_QUADRATIC_TRIANGLE;
100       else if ( theNbNodes == 8 )   return VTK_QUADRATIC_QUAD;
101       else return VTK_EMPTY_CELL;
102       
103     case SMDSAbs_Volume:
104       if (thePoly && theNbNodes>3 ) return VTK_CONVEX_POINT_SET;
105       else if ( theNbNodes == 4 )   return VTK_TETRA;
106       else if ( theNbNodes == 5 )   return VTK_PYRAMID;
107       else if ( theNbNodes == 6 )   return VTK_WEDGE;
108       else if ( theNbNodes == 8 )   return VTK_HEXAHEDRON;
109       else if ( theNbNodes == 10 )  {
110         return VTK_QUADRATIC_TETRA;
111       }
112       else if ( theNbNodes == 20 )  {
113         return VTK_QUADRATIC_HEXAHEDRON;
114       }
115       else if ( theNbNodes==13 || theNbNodes==15 )  {
116         return VTK_CONVEX_POINT_SET;
117       }
118       else return VTK_EMPTY_CELL;
119
120     default: return VTK_EMPTY_CELL;
121   }
122 }
123
124 //=================================================================================
125 // functions : SMESH_VisualObjDef
126 // purpose   : Constructor
127 //=================================================================================
128 SMESH_VisualObjDef::SMESH_VisualObjDef()
129 {
130   myGrid = vtkUnstructuredGrid::New();
131 }
132 SMESH_VisualObjDef::~SMESH_VisualObjDef()
133 {
134   if ( MYDEBUG )
135     MESSAGE( "~SMESH_MeshObj - myGrid->GetReferenceCount() = " << myGrid->GetReferenceCount() );
136   myGrid->Delete();
137 }
138
139 //=================================================================================
140 // functions : GetNodeObjId, GetNodeVTKId, GetElemObjId, GetElemVTKId
141 // purpose   : Methods for retrieving VTK IDs by SMDS IDs and  vice versa
142 //=================================================================================
143 vtkIdType SMESH_VisualObjDef::GetNodeObjId( int theVTKID )
144 {
145   return myVTK2SMDSNodes.find(theVTKID) == myVTK2SMDSNodes.end() ? -1 : myVTK2SMDSNodes[theVTKID];
146 }
147
148 vtkIdType SMESH_VisualObjDef::GetNodeVTKId( int theObjID )
149 {
150   return mySMDS2VTKNodes.find(theObjID) == mySMDS2VTKNodes.end() ? -1 : mySMDS2VTKNodes[theObjID];
151 }
152
153 vtkIdType SMESH_VisualObjDef::GetElemObjId( int theVTKID )
154 {
155   return myVTK2SMDSElems.find(theVTKID) == myVTK2SMDSElems.end() ? -1 : myVTK2SMDSElems[theVTKID];
156 }
157
158 vtkIdType SMESH_VisualObjDef::GetElemVTKId( int theObjID )
159 {
160   return mySMDS2VTKElems.find(theObjID) == mySMDS2VTKElems.end() ? -1 : mySMDS2VTKElems[theObjID];
161 }
162
163 //=================================================================================
164 // function : SMESH_VisualObjDef::createPoints
165 // purpose  : Create points from nodes
166 //=================================================================================
167 void SMESH_VisualObjDef::createPoints( vtkPoints* thePoints )
168 {
169   if ( thePoints == 0 )
170     return;
171
172   TEntityList aNodes;
173   vtkIdType nbNodes = GetEntities( SMDSAbs_Node, aNodes );
174   thePoints->SetNumberOfPoints( nbNodes );
175   
176   int nbPoints = 0;
177
178   TEntityList::const_iterator anIter;
179   for ( anIter = aNodes.begin(); anIter != aNodes.end(); ++anIter )
180   {
181     const SMDS_MeshNode* aNode = ( const SMDS_MeshNode* )(*anIter);
182     if ( aNode != 0 )
183     {
184       thePoints->SetPoint( nbPoints, aNode->X(), aNode->Y(), aNode->Z() );
185       int anId = aNode->GetID();
186       mySMDS2VTKNodes.insert( TMapOfIds::value_type( anId, nbPoints ) );
187       myVTK2SMDSNodes.insert( TMapOfIds::value_type( nbPoints, anId ) );
188       nbPoints++;
189     }
190   }
191
192   if ( nbPoints != nbNodes )
193     thePoints->SetNumberOfPoints( nbPoints );
194 }
195
196 //=================================================================================
197 // function : buildPrs
198 // purpose  : create VTK cells( fill unstructured grid )
199 //=================================================================================
200 void SMESH_VisualObjDef::buildPrs()
201 {
202   // PAL16631(crash after a mesh computation that failed because of lack of memory):
203   // Catch exceptions upper by stack
204 //   try 
205 //   {
206     mySMDS2VTKNodes.clear();
207     myVTK2SMDSNodes.clear();
208     mySMDS2VTKElems.clear();
209     myVTK2SMDSElems.clear();
210     
211     if ( IsNodePrs() )
212       buildNodePrs();
213     else
214       buildElemPrs();
215 //   }
216 //   catch( const std::exception& exc )
217 //   {
218 //     INFOS("Follow exception was cought:\n\t"<<exc.what());
219 //   }
220 //   catch(...)
221 //   {
222 //     INFOS("Unknown exception was cought !!!");
223 //   }
224   
225   if( MYDEBUG ) MESSAGE( "Update - myGrid->GetNumberOfCells() = "<<myGrid->GetNumberOfCells() );
226   if( MYDEBUGWITHFILES ) SMESH::WriteUnstructuredGrid( myGrid,"/tmp/buildPrs" );
227 }
228
229 //=================================================================================
230 // function : buildNodePrs
231 // purpose  : create VTK cells for nodes
232 //=================================================================================
233 void SMESH_VisualObjDef::buildNodePrs()
234 {
235   // PAL16631: without swap, bad_alloc is not thrown but hung up and crash instead,
236   // so check remaining memory size for safety
237   SMDS_Mesh::CheckMemory(); // PAL16631
238   vtkPoints* aPoints = vtkPoints::New();
239   createPoints( aPoints );
240   SMDS_Mesh::CheckMemory();
241   myGrid->SetPoints( aPoints );
242   aPoints->Delete();
243
244   myGrid->SetCells( 0, 0, 0 );
245 }
246
247 //=================================================================================
248 // function : buildElemPrs
249 // purpose  : Create VTK cells for elements
250 //=================================================================================
251
252 namespace{
253   typedef std::vector<const SMDS_MeshElement*> TConnect;
254
255   int GetConnect(const SMDS_ElemIteratorPtr& theNodesIter, 
256                  TConnect& theConnect)
257   {
258     theConnect.clear();
259     for(; theNodesIter->more();)
260       theConnect.push_back(theNodesIter->next());
261     return theConnect.size();
262   }
263   
264   inline 
265   void SetId(vtkIdList *theIdList, 
266              const SMESH_VisualObjDef::TMapOfIds& theSMDS2VTKNodes, 
267              const TConnect& theConnect, 
268              int thePosition,
269              int theId)
270   {
271     theIdList->SetId(thePosition,theSMDS2VTKNodes.find(theConnect[theId]->GetID())->second);
272   }
273
274 }
275
276
277 void SMESH_VisualObjDef::buildElemPrs()
278 {
279   // Create points
280   
281   vtkPoints* aPoints = vtkPoints::New();
282   createPoints( aPoints );
283   myGrid->SetPoints( aPoints );
284   aPoints->Delete();
285     
286   if ( MYDEBUG )
287     MESSAGE("Update - myGrid->GetNumberOfPoints() = "<<myGrid->GetNumberOfPoints());
288
289   // Calculate cells size
290
291   static SMDSAbs_ElementType aTypes[ 3 ] = { SMDSAbs_Edge, SMDSAbs_Face, SMDSAbs_Volume };
292
293   // get entity data
294   map<SMDSAbs_ElementType,int> nbEnts;
295   map<SMDSAbs_ElementType,TEntityList> anEnts;
296
297   for ( int i = 0; i <= 2; i++ )
298     nbEnts[ aTypes[ i ] ] = GetEntities( aTypes[ i ], anEnts[ aTypes[ i ] ] );
299
300   // PAL16631: without swap, bad_alloc is not thrown but hung up and crash instead,
301   // so check remaining memory size for safety
302   SMDS_Mesh::CheckMemory(); // PAL16631
303
304   vtkIdType aCellsSize =  3 * nbEnts[ SMDSAbs_Edge ];
305
306   for ( int i = 1; i <= 2; i++ ) // iterate through faces and volumes
307   {
308     if ( nbEnts[ aTypes[ i ] ] )
309     {
310       const TEntityList& aList = anEnts[ aTypes[ i ] ];
311       TEntityList::const_iterator anIter;
312       for ( anIter = aList.begin(); anIter != aList.end(); ++anIter )
313         aCellsSize += (*anIter)->NbNodes() + 1;
314     }
315   }
316
317   vtkIdType aNbCells = nbEnts[ SMDSAbs_Edge ] + nbEnts[ SMDSAbs_Face ] + nbEnts[ SMDSAbs_Volume ];
318   
319   if ( MYDEBUG )
320     MESSAGE( "Update - aNbCells = "<<aNbCells<<"; aCellsSize = "<<aCellsSize );
321
322   // Create cells
323   
324   vtkCellArray* aConnectivity = vtkCellArray::New();
325   aConnectivity->Allocate( aCellsSize, 0 );
326   
327   SMDS_Mesh::CheckMemory(); // PAL16631
328
329   vtkUnsignedCharArray* aCellTypesArray = vtkUnsignedCharArray::New();
330   aCellTypesArray->SetNumberOfComponents( 1 );
331   aCellTypesArray->Allocate( aNbCells * aCellTypesArray->GetNumberOfComponents() );
332   
333   SMDS_Mesh::CheckMemory(); // PAL16631
334
335   vtkIdList *anIdList = vtkIdList::New();
336   vtkIdType iElem = 0;
337
338   TConnect aConnect;
339   aConnect.reserve(VTK_CELL_SIZE);
340
341   SMDS_Mesh::CheckMemory(); // PAL16631
342
343   for ( int i = 0; i <= 2; i++ ) // iterate through edges, faces and volumes
344   {
345     if( nbEnts[ aTypes[ i ] ] > 0 )
346     {
347       const SMDSAbs_ElementType& aType = aTypes[ i ];
348       const TEntityList& aList = anEnts[ aType ];
349       TEntityList::const_iterator anIter;
350       for ( anIter = aList.begin(); anIter != aList.end(); ++anIter )
351       {
352         const SMDS_MeshElement* anElem = *anIter;
353         
354         vtkIdType aNbNodes = anElem->NbNodes();
355         anIdList->SetNumberOfIds( aNbNodes );
356
357         int anId = anElem->GetID();
358
359         mySMDS2VTKElems.insert( TMapOfIds::value_type( anId, iElem ) );
360         myVTK2SMDSElems.insert( TMapOfIds::value_type( iElem, anId ) );
361
362         SMDS_ElemIteratorPtr aNodesIter = anElem->nodesIterator();
363         switch(aType){
364         case SMDSAbs_Volume:{
365           aConnect.clear();
366           std::vector<int> aConnectivities;
367           // Convertions connectivities from SMDS to VTK
368           if (anElem->IsPoly() && aNbNodes > 3) { // POLYEDRE
369
370             if ( const SMDS_PolyhedralVolumeOfNodes* ph =
371                  dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*> (anElem))
372             {
373               aNbNodes = GetConnect(ph->uniqueNodesIterator(),aConnect);
374               anIdList->SetNumberOfIds( aNbNodes );
375             }
376             for (int k = 0; k < aNbNodes; k++)
377               aConnectivities.push_back(k);
378
379           } else if (aNbNodes == 4) {
380             static int anIds[] = {0,2,1,3};
381             for (int k = 0; k < aNbNodes; k++) aConnectivities.push_back(anIds[k]);
382
383           } else if (aNbNodes == 5) {
384             static int anIds[] = {0,3,2,1,4};
385             for (int k = 0; k < aNbNodes; k++) aConnectivities.push_back(anIds[k]);
386
387           } else if (aNbNodes == 6) {
388             static int anIds[] = {0,1,2,3,4,5};
389             for (int k = 0; k < aNbNodes; k++) aConnectivities.push_back(anIds[k]);
390
391           }
392           else if (aNbNodes == 8) {
393             static int anIds[] = {0,3,2,1,4,7,6,5};
394             for (int k = 0; k < aNbNodes; k++) aConnectivities.push_back(anIds[k]);
395
396           }
397           else if (aNbNodes == 10) {
398             static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
399             for (int k = 0; k < aNbNodes; k++) aConnectivities.push_back(anIds[k]);
400           }
401           else if (aNbNodes == 13) {
402             static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
403             for (int k = 0; k < aNbNodes; k++) aConnectivities.push_back(anIds[k]);
404           }
405           else if (aNbNodes == 15) {
406             static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
407             for (int k = 0; k < aNbNodes; k++) aConnectivities.push_back(anIds[k]);
408             //for (int k = 0; k < aNbNodes; k++) {
409             //  int nn = aConnectivities[k];
410             //  const SMDS_MeshNode* N = static_cast<const SMDS_MeshNode*> (aConnect[nn]);
411             //  cout<<"k="<<k<<"  N("<<N->X()<<","<<N->Y()<<","<<N->Z()<<")"<<endl;
412             //}
413           }
414           else if (aNbNodes == 20) {
415             static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
416             for (int k = 0; k < aNbNodes; k++) aConnectivities.push_back(anIds[k]);
417           }
418           else {
419           }
420
421           if ( aConnect.empty() )
422             GetConnect(aNodesIter,aConnect);
423
424           if (aConnectivities.size() > 0) {
425             for (vtkIdType aNodeId = 0; aNodeId < aNbNodes; aNodeId++)
426               SetId(anIdList,mySMDS2VTKNodes,aConnect,aNodeId,aConnectivities[aNodeId]);
427           }
428           break;
429         }
430         default:
431           for( vtkIdType aNodeId = 0; aNodesIter->more(); aNodeId++ ){
432             const SMDS_MeshElement* aNode = aNodesIter->next();
433             anIdList->SetId( aNodeId, mySMDS2VTKNodes[aNode->GetID()] );
434           }
435         }
436
437         aConnectivity->InsertNextCell( anIdList );
438         aCellTypesArray->InsertNextValue( getCellType( aType, anElem->IsPoly(), aNbNodes ) );
439
440         iElem++;
441       }
442     }
443     SMDS_Mesh::CheckMemory(); // PAL16631
444   }
445
446   // Insert cells in grid
447   
448   VTKViewer_CellLocationsArray* aCellLocationsArray = VTKViewer_CellLocationsArray::New();
449   aCellLocationsArray->SetNumberOfComponents( 1 );
450   aCellLocationsArray->SetNumberOfTuples( aNbCells );
451   
452   SMDS_Mesh::CheckMemory(); // PAL16631
453
454   aConnectivity->InitTraversal();
455   for( vtkIdType idType = 0, *pts, npts; aConnectivity->GetNextCell( npts, pts ); idType++ )
456     aCellLocationsArray->SetValue( idType, aConnectivity->GetTraversalLocation( npts ) );
457
458   myGrid->SetCells( aCellTypesArray, aCellLocationsArray,aConnectivity );
459   
460   aCellLocationsArray->Delete();
461   aCellTypesArray->Delete();
462   aConnectivity->Delete();
463   anIdList->Delete();
464
465   SMDS_Mesh::CheckMemory(); // PAL16631
466 }
467
468 //=================================================================================
469 // function : GetEdgeNodes
470 // purpose  : Retrieve ids of nodes from edge of elements ( edge is numbered from 1 )
471 //=================================================================================
472 bool SMESH_VisualObjDef::GetEdgeNodes( const int theElemId,
473                                        const int theEdgeNum,
474                                        int&      theNodeId1,
475                                        int&      theNodeId2 ) const
476 {
477   const SMDS_Mesh* aMesh = GetMesh();
478   if ( aMesh == 0 )
479     return false;
480     
481   const SMDS_MeshElement* anElem = aMesh->FindElement( theElemId );
482   if ( anElem == 0 )
483     return false;
484     
485   int nbNodes = anElem->NbNodes();
486
487   if ( theEdgeNum < 0 || theEdgeNum > 3 || nbNodes != 3 && nbNodes != 4 || theEdgeNum > nbNodes )
488     return false;
489
490   vector<int> anIds( nbNodes );
491   SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
492   int i = 0;
493   while( anIter->more() )
494     anIds[ i++ ] = anIter->next()->GetID();
495
496   if ( theEdgeNum < nbNodes - 1 )
497   {
498     theNodeId1 = anIds[ theEdgeNum ];
499     theNodeId2 = anIds[ theEdgeNum + 1 ];
500   }
501   else
502   {
503     theNodeId1 = anIds[ nbNodes - 1 ];
504     theNodeId2 = anIds[ 0 ];
505   }
506
507   return true;
508 }
509
510 /*
511   Class       : SMESH_MeshObj
512   Description : Class for visualisation of mesh
513 */
514
515 //=================================================================================
516 // function : SMESH_MeshObj
517 // purpose  : Constructor
518 //=================================================================================
519 SMESH_MeshObj::SMESH_MeshObj(SMESH::SMESH_Mesh_ptr theMesh):
520   myClient(SalomeApp_Application::orb(),theMesh)
521 {
522   if ( MYDEBUG ) 
523     MESSAGE("SMESH_MeshObj - this = "<<this<<"; theMesh->_is_nil() = "<<theMesh->_is_nil());
524 }
525
526 //=================================================================================
527 // function : ~SMESH_MeshObj
528 // purpose  : Destructor
529 //=================================================================================
530 SMESH_MeshObj::~SMESH_MeshObj()
531 {
532   if ( MYDEBUG ) 
533     MESSAGE("SMESH_MeshObj - this = "<<this<<"\n");
534 }
535
536 //=================================================================================
537 // function : Update
538 // purpose  : Update mesh and fill grid with new values if necessary 
539 //=================================================================================
540 bool SMESH_MeshObj::Update( int theIsClear )
541 {
542   // Update SMDS_Mesh on client part
543   if ( myClient.Update(theIsClear) || GetUnstructuredGrid()->GetNumberOfPoints()==0) {
544     buildPrs();  // Fill unstructured grid
545     return true;
546   }
547   return false;
548 }
549
550 //=================================================================================
551 // function : GetElemDimension
552 // purpose  : Get dimension of element
553 //=================================================================================
554 int SMESH_MeshObj::GetElemDimension( const int theObjId )
555 {
556   const SMDS_MeshElement* anElem = myClient->FindElement( theObjId );
557   if ( anElem == 0 )
558     return 0;
559
560   int aType = anElem->GetType();
561   switch ( aType )
562   {
563     case SMDSAbs_Edge  : return 1;
564     case SMDSAbs_Face  : return 2;
565     case SMDSAbs_Volume: return 3;
566     default            : return 0;
567   }
568 }
569
570 //=================================================================================
571 // function : GetEntities
572 // purpose  : Get entities of specified type. Return number of entities
573 //=================================================================================
574 int SMESH_MeshObj::GetNbEntities( const SMDSAbs_ElementType theType) const
575 {
576   switch ( theType )
577   {
578     case SMDSAbs_Node:
579     {
580       return myClient->NbNodes();
581     }
582     break;
583     case SMDSAbs_Edge:
584     {
585       return myClient->NbEdges();
586     }
587     break;
588     case SMDSAbs_Face:
589     {
590       return myClient->NbFaces();
591     }
592     break;
593     case SMDSAbs_Volume:
594     {
595       return myClient->NbVolumes();
596     }
597     break;
598     default:
599       return 0;
600     break;
601   }
602 }
603
604 int SMESH_MeshObj::GetEntities( const SMDSAbs_ElementType theType, TEntityList& theObjs ) const
605 {
606   theObjs.clear();
607
608   switch ( theType )
609   {
610     case SMDSAbs_Node:
611     {
612       SMDS_NodeIteratorPtr anIter = myClient->nodesIterator();
613       while ( anIter->more() ) theObjs.push_back( anIter->next() );
614     }
615     break;
616     case SMDSAbs_Edge:
617     {
618       SMDS_EdgeIteratorPtr anIter = myClient->edgesIterator();
619       while ( anIter->more() ) theObjs.push_back( anIter->next() );
620     }
621     break;
622     case SMDSAbs_Face:
623     {
624       SMDS_FaceIteratorPtr anIter = myClient->facesIterator();
625       while ( anIter->more() ) theObjs.push_back( anIter->next() );
626     }
627     break;
628     case SMDSAbs_Volume:
629     {
630       SMDS_VolumeIteratorPtr anIter = myClient->volumesIterator();
631       while ( anIter->more() ) theObjs.push_back( anIter->next() );
632     }
633     break;
634     default:
635     break;
636   }
637
638   return theObjs.size();
639 }
640
641 //=================================================================================
642 // function : UpdateFunctor
643 // purpose  : Update functor in accordance with current mesh
644 //=================================================================================
645 void SMESH_MeshObj::UpdateFunctor( const SMESH::Controls::FunctorPtr& theFunctor )
646 {
647   theFunctor->SetMesh( GetMesh() );
648 }
649
650 //=================================================================================
651 // function : IsNodePrs
652 // purpose  : Return true if node presentation is used
653 //=================================================================================
654 bool SMESH_MeshObj::IsNodePrs() const
655 {
656   return myClient->NbEdges() == 0 &&myClient->NbFaces() == 0 && myClient->NbVolumes() == 0 ;
657 }
658
659
660 /*
661   Class       : SMESH_SubMeshObj
662   Description : Base class for visualisation of submeshes and groups
663 */
664
665 //=================================================================================
666 // function : SMESH_SubMeshObj
667 // purpose  : Constructor
668 //=================================================================================
669 SMESH_SubMeshObj::SMESH_SubMeshObj( SMESH_MeshObj* theMeshObj )
670 {
671   if ( MYDEBUG ) MESSAGE( "SMESH_SubMeshObj - theMeshObj = " << theMeshObj );
672   
673   myMeshObj = theMeshObj;
674 }
675
676 SMESH_SubMeshObj::~SMESH_SubMeshObj()
677 {
678 }
679
680 //=================================================================================
681 // function : GetElemDimension
682 // purpose  : Get dimension of element
683 //=================================================================================
684 int SMESH_SubMeshObj::GetElemDimension( const int theObjId )
685 {
686   return myMeshObj == 0 ? 0 : myMeshObj->GetElemDimension( theObjId );
687 }
688
689 //=================================================================================
690 // function : UpdateFunctor
691 // purpose  : Update functor in accordance with current mesh
692 //=================================================================================
693 void SMESH_SubMeshObj::UpdateFunctor( const SMESH::Controls::FunctorPtr& theFunctor )
694 {
695   theFunctor->SetMesh( myMeshObj->GetMesh() );
696 }
697
698 //=================================================================================
699 // function : Update
700 // purpose  : Update mesh object and fill grid with new values 
701 //=================================================================================
702 bool SMESH_SubMeshObj::Update( int theIsClear )
703 {
704   bool changed = myMeshObj->Update( theIsClear );
705   buildPrs();
706   return changed;
707 }
708
709
710 /*
711   Class       : SMESH_GroupObj
712   Description : Class for visualisation of groups
713 */
714
715 //=================================================================================
716 // function : SMESH_GroupObj
717 // purpose  : Constructor
718 //=================================================================================
719 SMESH_GroupObj::SMESH_GroupObj( SMESH::SMESH_GroupBase_ptr theGroup, 
720                                 SMESH_MeshObj*             theMeshObj )
721 : SMESH_SubMeshObj( theMeshObj ),
722   myGroupServer( SMESH::SMESH_GroupBase::_duplicate(theGroup) )
723 {
724   if ( MYDEBUG ) MESSAGE("SMESH_GroupObj - theGroup->_is_nil() = "<<theGroup->_is_nil());
725   myGroupServer->Register();
726 }
727
728 SMESH_GroupObj::~SMESH_GroupObj()
729 {
730   if ( MYDEBUG ) MESSAGE("~SMESH_GroupObj");
731   myGroupServer->Destroy();
732 }
733
734 //=================================================================================
735 // function : IsNodePrs
736 // purpose  : Return true if node presentation is used
737 //=================================================================================
738 bool SMESH_GroupObj::IsNodePrs() const
739 {
740   return myGroupServer->GetType() == SMESH::NODE;
741 }
742
743 //=================================================================================
744 // function : getNodesFromElems
745 // purpose  : Retrieve nodes from elements
746 //=================================================================================
747 static int getNodesFromElems( SMESH::long_array_var&              theElemIds,
748                               const SMDS_Mesh*                    theMesh,
749                               std::list<const SMDS_MeshElement*>& theResList )
750 {
751   set<const SMDS_MeshElement*> aNodeSet;
752
753   for ( CORBA::Long i = 0, n = theElemIds->length(); i < n; i++ )
754   {
755     const SMDS_MeshElement* anElem = theMesh->FindElement( theElemIds[ i ] );
756     if ( anElem != 0 )
757     {
758       SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
759       while ( anIter->more() )
760       {
761         const SMDS_MeshElement* aNode = anIter->next();
762         if ( aNode != 0 )
763           aNodeSet.insert( aNode );
764       }
765     }
766   }
767
768   set<const SMDS_MeshElement*>::const_iterator anIter;
769   for ( anIter = aNodeSet.begin(); anIter != aNodeSet.end(); ++anIter )
770     theResList.push_back( *anIter );
771
772   return theResList.size();    
773 }
774
775 //=================================================================================
776 // function : getPointers
777 // purpose  : Get std::list<const SMDS_MeshElement*> from list of IDs
778 //=================================================================================
779 static int getPointers( const SMDSAbs_ElementType            theRequestType,
780                         SMESH::long_array_var&              theElemIds,
781                         const SMDS_Mesh*                    theMesh,
782                         std::list<const SMDS_MeshElement*>& theResList )
783 {
784   for ( CORBA::Long i = 0, n = theElemIds->length(); i < n; i++ )
785   {
786     const SMDS_MeshElement* anElem = theRequestType == SMDSAbs_Node
787       ? theMesh->FindNode( theElemIds[ i ] ) : theMesh->FindElement( theElemIds[ i ] );
788
789     if ( anElem != 0 )
790       theResList.push_back( anElem );
791   }
792
793   return theResList.size();
794 }
795
796
797 //=================================================================================
798 // function : GetEntities
799 // purpose  : Get entities of specified type. Return number of entities
800 //=================================================================================
801 int SMESH_GroupObj::GetNbEntities( const SMDSAbs_ElementType theType) const
802 {
803   if(SMDSAbs_ElementType(myGroupServer->GetType()) == theType){
804     return myGroupServer->Size();
805   }
806   return 0;
807 }
808
809 int SMESH_GroupObj::GetEntities( const SMDSAbs_ElementType theType, TEntityList& theResList ) const
810 {
811   theResList.clear();
812   SMDS_Mesh* aMesh = myMeshObj->GetMesh();
813   
814   if ( myGroupServer->Size() == 0 || aMesh == 0 )
815     return 0;
816
817   SMDSAbs_ElementType aGrpType = SMDSAbs_ElementType(myGroupServer->GetType());
818   SMESH::long_array_var anIds = myGroupServer->GetListOfID();
819
820   if ( aGrpType == theType )
821     return getPointers( theType, anIds, aMesh, theResList );
822   else if ( theType == SMDSAbs_Node )
823     return getNodesFromElems( anIds, aMesh, theResList );
824   else
825     return 0;
826 }    
827
828
829
830 /*
831   Class       : SMESH_subMeshObj
832   Description : Class for visualisation of submeshes
833 */
834
835 //=================================================================================
836 // function : SMESH_subMeshObj
837 // purpose  : Constructor
838 //=================================================================================
839 SMESH_subMeshObj::SMESH_subMeshObj( SMESH::SMESH_subMesh_ptr theSubMesh,
840                                     SMESH_MeshObj*           theMeshObj )
841 : SMESH_SubMeshObj( theMeshObj ),
842   mySubMeshServer( SMESH::SMESH_subMesh::_duplicate( theSubMesh ) )
843 {
844   if ( MYDEBUG ) MESSAGE( "SMESH_subMeshObj - theSubMesh->_is_nil() = " << theSubMesh->_is_nil() );
845   
846   mySubMeshServer->Register();
847 }
848
849 SMESH_subMeshObj::~SMESH_subMeshObj()
850 {
851   if ( MYDEBUG ) MESSAGE( "~SMESH_subMeshObj" );
852   mySubMeshServer->Destroy();
853 }
854
855 //=================================================================================
856 // function : GetEntities
857 // purpose  : Get entities of specified type. Return number of entities
858 //=================================================================================
859 int SMESH_subMeshObj::GetNbEntities( const SMDSAbs_ElementType theType) const
860 {
861   switch ( theType )
862   {
863     case SMDSAbs_Node:
864     {
865       return mySubMeshServer->GetNumberOfNodes( false );
866     }
867     break;
868     case SMDSAbs_Edge:
869     case SMDSAbs_Face:
870     case SMDSAbs_Volume:
871     {
872       SMESH::long_array_var anIds = 
873         mySubMeshServer->GetElementsByType( SMESH::ElementType(theType) );
874       return anIds->length();
875     }
876     default:
877       return 0;
878     break;
879   }
880 }
881
882 int SMESH_subMeshObj::GetEntities( const SMDSAbs_ElementType theType, TEntityList& theResList ) const
883 {
884   theResList.clear();
885
886   SMDS_Mesh* aMesh = myMeshObj->GetMesh();
887   if ( aMesh == 0 )
888     return 0;
889
890   bool isNodal = IsNodePrs();
891
892   if ( isNodal )
893   {
894     if ( theType == SMDSAbs_Node )
895     {
896       SMESH::long_array_var anIds = mySubMeshServer->GetNodesId();
897       return getPointers( SMDSAbs_Node, anIds, aMesh, theResList );
898     }
899   }
900   else
901   {
902     if ( theType == SMDSAbs_Node )
903     {
904       SMESH::long_array_var anIds = mySubMeshServer->GetElementsId();
905       return getNodesFromElems( anIds, aMesh, theResList );
906     }
907     else
908     {
909       SMESH::long_array_var anIds = 
910         mySubMeshServer->GetElementsByType( SMESH::ElementType(theType) );
911       return getPointers( theType, anIds, aMesh, theResList );
912     }
913   }
914
915   return 0;
916 }
917
918 //=================================================================================
919 // function : IsNodePrs
920 // purpose  : Return true if node presentation is used
921 //=================================================================================
922 bool SMESH_subMeshObj::IsNodePrs() const
923 {
924   return mySubMeshServer->GetNumberOfElements() == 0;
925 }