Salome HOME
c12d63bfa68c6d733b7632f80495b6a7da527ed3
[modules/smesh.git] / src / OBJECT / SMESH_Object.cxx
1 // Copyright (C) 2007-2011  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.
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 //  SMESH OBJECT : interactive object for SMESH visualization
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 = 1;
68 static int MYDEBUGWITHFILES = 0;//1;
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_0DElement: 
91       return VTK_VERTEX;
92
93     case SMDSAbs_Edge: 
94       if( theNbNodes == 2 )         return VTK_LINE;
95       else if ( theNbNodes == 3 )   return VTK_QUADRATIC_EDGE;
96       else return VTK_EMPTY_CELL;
97
98     case SMDSAbs_Face  :
99       if (thePoly && theNbNodes>2 ) return VTK_POLYGON;
100       else if ( theNbNodes == 3 )   return VTK_TRIANGLE;
101       else if ( theNbNodes == 4 )   return VTK_QUAD;
102       else if ( theNbNodes == 6 )   return VTK_QUADRATIC_TRIANGLE;
103       else if ( theNbNodes == 8 )   return VTK_QUADRATIC_QUAD;
104       else return VTK_EMPTY_CELL;
105       
106     case SMDSAbs_Volume:
107       if (thePoly && theNbNodes>3 ) return VTK_POLYHEDRON; //VTK_CONVEX_POINT_SET;
108       else if ( theNbNodes == 4 )   return VTK_TETRA;
109       else if ( theNbNodes == 5 )   return VTK_PYRAMID;
110       else if ( theNbNodes == 6 )   return VTK_WEDGE;
111       else if ( theNbNodes == 8 )   return VTK_HEXAHEDRON;
112       else if ( theNbNodes == 10 )  {
113         return VTK_QUADRATIC_TETRA;
114       }
115       else if ( theNbNodes == 20 )  {
116         return VTK_QUADRATIC_HEXAHEDRON;
117       }
118       else if ( theNbNodes == 15 )  {
119         return VTK_QUADRATIC_WEDGE;
120       }
121       else if ( theNbNodes==13 )  {
122         return VTK_QUADRATIC_PYRAMID; //VTK_CONVEX_POINT_SET;
123       }
124       else return VTK_EMPTY_CELL;
125
126     default: return VTK_EMPTY_CELL;
127   }
128 }
129
130 //=================================================================================
131 // functions : SMESH_VisualObjDef
132 // purpose   : Constructor
133 //=================================================================================
134 SMESH_VisualObjDef::SMESH_VisualObjDef()
135 {
136   MESSAGE("---------------------------------------------SMESH_VisualObjDef::SMESH_VisualObjDef");
137   myGrid = vtkUnstructuredGrid::New();
138   myLocalGrid = false;
139   ClearEntitiesFlags();
140   SMESH::GetEntitiesFromObject(NULL);
141 }
142 SMESH_VisualObjDef::~SMESH_VisualObjDef()
143 {
144   MESSAGE("---------------------------------------------SMESH_VisualObjDef::~SMESH_VisualObjDef");
145   //if ( MYDEBUG )
146     MESSAGE( "~SMESH_MeshObj - myGrid->GetReferenceCount() = " << myGrid->GetReferenceCount() );
147   myGrid->Delete();
148 }
149
150 //=================================================================================
151 // functions : GetNodeObjId, GetNodeVTKId, GetElemObjId, GetElemVTKId
152 // purpose   : Methods for retrieving VTK IDs by SMDS IDs and  vice versa
153 //=================================================================================
154 vtkIdType SMESH_VisualObjDef::GetNodeObjId( int theVTKID )
155 {
156         if (myLocalGrid)
157         {
158                 TMapOfIds::const_iterator i = myVTK2SMDSNodes.find(theVTKID);
159                 return i == myVTK2SMDSNodes.end() ? -1 : i->second;
160         }
161   return this->GetMesh()->FindNodeVtk(theVTKID)->GetID();
162 }
163
164 vtkIdType SMESH_VisualObjDef::GetNodeVTKId( int theObjID )
165 {
166         if (myLocalGrid)
167         {
168                 TMapOfIds::const_iterator i = mySMDS2VTKNodes.find(theObjID);
169     return i == mySMDS2VTKNodes.end() ? -1 : i->second;
170         }
171
172         const SMDS_MeshNode* aNode = 0;
173         if( this->GetMesh() ) {
174           aNode = this->GetMesh()->FindNode(theObjID);
175         }
176         return aNode ? aNode->getVtkId() : -1;
177 }
178
179 vtkIdType SMESH_VisualObjDef::GetElemObjId( int theVTKID )
180 {
181         if (myLocalGrid)
182         {
183                 TMapOfIds::const_iterator i = myVTK2SMDSElems.find(theVTKID);
184                 return i == myVTK2SMDSElems.end() ? -1 : i->second;
185         }
186   return this->GetMesh()->fromVtkToSmds(theVTKID);
187 }
188
189 vtkIdType SMESH_VisualObjDef::GetElemVTKId( int theObjID )
190 {
191         if (myLocalGrid)
192         {
193                 TMapOfIds::const_iterator i = mySMDS2VTKElems.find(theObjID);
194                 return i == mySMDS2VTKElems.end() ? -1 : i->second;
195         }
196   return this->GetMesh()->FindElement(theObjID)->getVtkId();
197   //return this->GetMesh()->fromSmdsToVtk(theObjID);
198 }
199
200 //=================================================================================
201 // function : SMESH_VisualObjDef::createPoints
202 // purpose  : Create points from nodes
203 //=================================================================================
204 /*! fills a vtkPoints structure for a submesh.
205  *  fills a std::list of SMDS_MeshElements*, then extract the points.
206  *  fills also conversion id maps between SMDS and VTK.
207  */
208 void SMESH_VisualObjDef::createPoints( vtkPoints* thePoints )
209 {
210   if ( thePoints == 0 )
211     return;
212
213   TEntityList aNodes;
214   vtkIdType nbNodes = GetEntities( SMDSAbs_Node, aNodes );
215   thePoints->SetNumberOfPoints( nbNodes );
216
217   int nbPoints = 0;
218
219   TEntityList::const_iterator anIter;
220   for ( anIter = aNodes.begin(); anIter != aNodes.end(); ++anIter )
221   {
222     const SMDS_MeshNode* aNode = ( const SMDS_MeshNode* )(*anIter);
223     if ( aNode != 0 )
224     {
225       thePoints->SetPoint( nbPoints, aNode->X(), aNode->Y(), aNode->Z() );
226       int anId = aNode->GetID();
227       mySMDS2VTKNodes.insert( TMapOfIds::value_type( anId, nbPoints ) );
228       myVTK2SMDSNodes.insert( TMapOfIds::value_type( nbPoints, anId ) );
229       nbPoints++;
230     }
231   }
232
233   if ( nbPoints != nbNodes )
234     thePoints->SetNumberOfPoints( nbPoints );
235 }
236
237 //=================================================================================
238 // function : buildPrs
239 // purpose  : create VTK cells( fill unstructured grid )
240 //=================================================================================
241 void SMESH_VisualObjDef::buildPrs(bool buildGrid)
242 {
243   MESSAGE("----------------------------------------------------------SMESH_VisualObjDef::buildPrs " << buildGrid);
244   if (buildGrid)
245   {
246         myLocalGrid = true;
247         try
248         {
249                 mySMDS2VTKNodes.clear();
250                 myVTK2SMDSNodes.clear();
251                 mySMDS2VTKElems.clear();
252                 myVTK2SMDSElems.clear();
253
254                 if ( IsNodePrs() )
255                         buildNodePrs();
256                 else
257                         buildElemPrs();
258         }
259         catch(...)
260         {
261                 mySMDS2VTKNodes.clear();
262                 myVTK2SMDSNodes.clear();
263                 mySMDS2VTKElems.clear();
264                 myVTK2SMDSElems.clear();
265
266                 myGrid->SetPoints( 0 );
267                 myGrid->SetCells( 0, 0, 0, 0, 0 );
268                 throw;
269         }
270   }
271   else
272   {
273         myLocalGrid = false;
274         if (!GetMesh()->isCompacted())
275           {
276             MESSAGE("*** buildPrs ==> compactMesh!");
277             GetMesh()->compactMesh();
278           }
279         vtkUnstructuredGrid *theGrid = GetMesh()->getGrid();
280         updateEntitiesFlags();
281         myGrid->ShallowCopy(theGrid);
282         //MESSAGE(myGrid->GetReferenceCount());
283         //MESSAGE( "Update - myGrid->GetNumberOfCells() = "<<myGrid->GetNumberOfCells() );
284         //MESSAGE( "Update - myGrid->GetNumberOfPoints() = "<<myGrid->GetNumberOfPoints() );
285         if( MYDEBUGWITHFILES ) SMESH::WriteUnstructuredGrid( myGrid,"buildPrs.vtu" );
286   }
287 }
288
289 //=================================================================================
290 // function : buildNodePrs
291 // purpose  : create VTK cells for nodes
292 //=================================================================================
293
294 void SMESH_VisualObjDef::buildNodePrs()
295 {
296   // PAL16631: without swap, bad_alloc is not thrown but hung up and crash instead,
297   // so check remaining memory size for safety
298   SMDS_Mesh::CheckMemory(); // PAL16631
299   vtkPoints* aPoints = vtkPoints::New();
300   createPoints( aPoints );
301   SMDS_Mesh::CheckMemory();
302   myGrid->SetPoints( aPoints );
303   aPoints->Delete();
304
305   myGrid->SetCells( 0, 0, 0, 0, 0 );
306 }
307
308 //=================================================================================
309 // function : buildElemPrs
310 // purpose  : Create VTK cells for elements
311 //=================================================================================
312
313 namespace{
314   typedef std::vector<const SMDS_MeshElement*> TConnect;
315
316   int GetConnect(const SMDS_ElemIteratorPtr& theNodesIter, 
317                  TConnect& theConnect)
318   {
319     theConnect.clear();
320     for(; theNodesIter->more();)
321       theConnect.push_back(theNodesIter->next());
322     return theConnect.size();
323   }
324   
325   inline 
326   void SetId(vtkIdList *theIdList, 
327              const SMESH_VisualObjDef::TMapOfIds& theSMDS2VTKNodes, 
328              const TConnect& theConnect, 
329              int thePosition,
330              int theId)
331   {
332     theIdList->SetId(thePosition,theSMDS2VTKNodes.find(theConnect[theId]->GetID())->second);
333   }
334
335 }
336
337
338 void SMESH_VisualObjDef::buildElemPrs()
339 {
340   // Create points
341
342   vtkPoints* aPoints = vtkPoints::New();
343   createPoints( aPoints );
344   myGrid->SetPoints( aPoints );
345   aPoints->Delete();
346
347   if ( MYDEBUG )
348     MESSAGE("Update - myGrid->GetNumberOfPoints() = "<<myGrid->GetNumberOfPoints());
349
350   // Calculate cells size
351
352   static SMDSAbs_ElementType aTypes[ 4 ] =
353     { SMDSAbs_0DElement, SMDSAbs_Edge, SMDSAbs_Face, SMDSAbs_Volume };
354
355   // get entity data
356   map<SMDSAbs_ElementType,int> nbEnts;
357   map<SMDSAbs_ElementType,TEntityList> anEnts;
358
359   for ( int i = 0; i <= 3; i++ )
360     nbEnts[ aTypes[ i ] ] = GetEntities( aTypes[ i ], anEnts[ aTypes[ i ] ] );
361
362   // PAL16631: without swap, bad_alloc is not thrown but hung up and crash instead,
363   // so check remaining memory size for safety
364   SMDS_Mesh::CheckMemory(); // PAL16631
365
366   vtkIdType aCellsSize =  2 * nbEnts[ SMDSAbs_0DElement ] + 3 * nbEnts[ SMDSAbs_Edge ];
367
368   for ( int i = 2; i <= 3; i++ ) // iterate through faces and volumes
369   {
370     if ( nbEnts[ aTypes[ i ] ] )
371     {
372       const TEntityList& aList = anEnts[ aTypes[ i ] ];
373       TEntityList::const_iterator anIter;
374       for ( anIter = aList.begin(); anIter != aList.end(); ++anIter ) {
375         if((*anIter)->GetEntityType() != SMDSEntity_Polyhedra &&
376            (*anIter)->GetEntityType() != SMDSEntity_Quad_Polyhedra) {
377           aCellsSize += (*anIter)->NbNodes() + 1;
378         } 
379         // Special case for the VTK_POLYHEDRON:
380         // itsinput cellArray is of special format.
381         //  [nCellFaces, nFace0Pts, i, j, k, nFace1Pts, i, j, k, ...]   
382         else {
383           if( const SMDS_VtkVolume* ph = dynamic_cast<const SMDS_VtkVolume*>(*anIter) ) {
384             int nbFaces = ph->NbFaces();
385             aCellsSize += (1 + ph->NbFaces());
386             for( int i = 1; i <= nbFaces; i++ ) {
387               aCellsSize += ph->NbFaceNodes(i);
388             }
389           }
390         }
391       }
392     }
393   }
394   
395   vtkIdType aNbCells = nbEnts[ SMDSAbs_0DElement ] + nbEnts[ SMDSAbs_Edge ] +
396                        nbEnts[ SMDSAbs_Face ] + nbEnts[ SMDSAbs_Volume ];
397
398   if ( MYDEBUG )
399     MESSAGE( "Update - aNbCells = "<<aNbCells<<"; aCellsSize = "<<aCellsSize );
400
401   // Create cells
402
403   vtkCellArray* aConnectivity = vtkCellArray::New();
404   aConnectivity->Allocate( aCellsSize, 0 );
405
406   SMDS_Mesh::CheckMemory(); // PAL16631
407
408   vtkUnsignedCharArray* aCellTypesArray = vtkUnsignedCharArray::New();
409   aCellTypesArray->SetNumberOfComponents( 1 );
410   aCellTypesArray->Allocate( aNbCells * aCellTypesArray->GetNumberOfComponents() );
411
412   SMDS_Mesh::CheckMemory(); // PAL16631
413
414   vtkIdList *anIdList = vtkIdList::New();
415   vtkIdType iElem = 0;
416
417   TConnect aConnect;
418   aConnect.reserve(VTK_CELL_SIZE);
419
420   SMDS_Mesh::CheckMemory(); // PAL16631
421
422   for ( int i = 0; i <= 3; i++ ) // iterate through 0d elements, edges, faces and volumes
423   {
424     if ( nbEnts[ aTypes[ i ] ] > 0 ) {
425       
426       const SMDSAbs_ElementType& aType = aTypes[ i ];
427       const TEntityList& aList = anEnts[ aType ];
428       TEntityList::const_iterator anIter;
429       for ( anIter = aList.begin(); anIter != aList.end(); ++anIter )
430       {
431         const SMDS_MeshElement* anElem = *anIter;
432         
433         vtkIdType aNbNodes = anElem->NbNodes();
434         anIdList->SetNumberOfIds( aNbNodes );
435         
436         int anId = anElem->GetID();
437         
438         mySMDS2VTKElems.insert( TMapOfIds::value_type( anId, iElem ) );
439         myVTK2SMDSElems.insert( TMapOfIds::value_type( iElem, anId ) );
440         
441         SMDS_ElemIteratorPtr aNodesIter = anElem->nodesIterator();
442         switch (aType) {
443         case SMDSAbs_Volume: {
444           aConnect.clear();
445           std::vector<int> aConnectivities;
446           // Convertions connectivities from SMDS to VTK
447           
448           if (anElem->IsPoly() && aNbNodes > 3) { // POLYEDRE
449             anIdList->Reset();
450             if ( const SMDS_VtkVolume* ph = dynamic_cast<const SMDS_VtkVolume*>(anElem) ) {
451               int nbFaces = ph->NbFaces();
452               anIdList->InsertNextId(nbFaces);
453               for( int i = 1; i <= nbFaces; i++ ) {
454                 anIdList->InsertNextId(ph->NbFaceNodes(i));
455                 for(int j = 1; j <= ph->NbFaceNodes(i); j++) {
456                   const SMDS_MeshNode* n = ph->GetFaceNode(i,j);
457                   if(n) {
458                     anIdList->InsertNextId(mySMDS2VTKNodes[n->GetID()]);
459                   }
460                 }
461               }
462             }
463             
464           } else if (aNbNodes == 4) {
465             static int anIds[] = {0,2,1,3};
466             for (int k = 0; k < aNbNodes; k++) aConnectivities.push_back(anIds[k]);
467             
468           } else if (aNbNodes == 5) {
469             static int anIds[] = {0,3,2,1,4};
470             for (int k = 0; k < aNbNodes; k++) aConnectivities.push_back(anIds[k]);
471
472           } else if (aNbNodes == 6) {
473             static int anIds[] = {0,1,2,3,4,5};
474             for (int k = 0; k < aNbNodes; k++) aConnectivities.push_back(anIds[k]);
475
476           }
477           else if (aNbNodes == 8) {
478             static int anIds[] = {0,3,2,1,4,7,6,5};
479             for (int k = 0; k < aNbNodes; k++) aConnectivities.push_back(anIds[k]);
480
481           }
482           else if (aNbNodes == 10) {
483             static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
484             for (int k = 0; k < aNbNodes; k++) aConnectivities.push_back(anIds[k]);
485           }
486           else if (aNbNodes == 13) {
487             static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
488             for (int k = 0; k < aNbNodes; k++) aConnectivities.push_back(anIds[k]);
489           }
490           else if (aNbNodes == 15) {
491             //static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
492             static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14};
493             for (int k = 0; k < aNbNodes; k++) aConnectivities.push_back(anIds[k]);
494             //for (int k = 0; k < aNbNodes; k++) {
495             //  int nn = aConnectivities[k];
496             //  const SMDS_MeshNode* N = static_cast<const SMDS_MeshNode*> (aConnect[nn]);
497             //  cout<<"k="<<k<<"  N("<<N->X()<<","<<N->Y()<<","<<N->Z()<<")"<<endl;
498             //}
499           }
500           else if (aNbNodes == 20) {
501             static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
502             for (int k = 0; k < aNbNodes; k++) aConnectivities.push_back(anIds[k]);
503           }
504           else {
505           }
506
507           if (!(anElem->IsPoly() && aNbNodes > 3)) {
508             if ( aConnect.empty() )
509               GetConnect(aNodesIter,aConnect);
510
511             if (aConnectivities.size() > 0) {
512               for (vtkIdType aNodeId = 0; aNodeId < aNbNodes; aNodeId++)
513                 SetId(anIdList,mySMDS2VTKNodes,aConnect,aNodeId,aConnectivities[aNodeId]);
514             }
515           }
516           break;
517         }
518         default:
519           for( vtkIdType aNodeId = 0; aNodesIter->more(); aNodeId++ ){
520             const SMDS_MeshElement* aNode = aNodesIter->next();
521             anIdList->SetId( aNodeId, mySMDS2VTKNodes[aNode->GetID()] );
522           }
523         }
524
525         
526         aConnectivity->InsertNextCell( anIdList );
527         aCellTypesArray->InsertNextValue( getCellType( aType, anElem->IsPoly(), aNbNodes ) );
528
529         iElem++;
530       }
531     }
532     SMDS_Mesh::CheckMemory(); // PAL16631
533   }
534
535   // Insert cells in grid
536
537   VTKViewer_CellLocationsArray* aCellLocationsArray = VTKViewer_CellLocationsArray::New();
538   aCellLocationsArray->SetNumberOfComponents( 1 );
539   aCellLocationsArray->SetNumberOfTuples( aNbCells );
540
541   SMDS_Mesh::CheckMemory(); // PAL16631
542
543   aConnectivity->InitTraversal();
544   for( vtkIdType idType = 0, *pts, npts; aConnectivity->GetNextCell( npts, pts ); idType++ )
545     aCellLocationsArray->SetValue( idType, aConnectivity->GetTraversalLocation( npts ) );
546
547   myGrid->SetCells( aCellTypesArray, aCellLocationsArray,aConnectivity );
548
549   aCellLocationsArray->Delete();
550   aCellTypesArray->Delete();
551   aConnectivity->Delete();
552   anIdList->Delete();
553
554   SMDS_Mesh::CheckMemory(); // PAL16631
555 }
556
557 //=================================================================================
558 // function : GetEdgeNodes
559 // purpose  : Retrieve ids of nodes from edge of elements ( edge is numbered from 1 )
560 //=================================================================================
561 bool SMESH_VisualObjDef::GetEdgeNodes( const int theElemId,
562                                        const int theEdgeNum,
563                                        int&      theNodeId1,
564                                        int&      theNodeId2 ) const
565 {
566   const SMDS_Mesh* aMesh = GetMesh();
567   if ( aMesh == 0 )
568     return false;
569     
570   const SMDS_MeshElement* anElem = aMesh->FindElement( theElemId );
571   if ( anElem == 0 )
572     return false;
573     
574   int nbNodes = anElem->NbNodes();
575
576   if ( theEdgeNum < 0 || theEdgeNum > 3 || (nbNodes != 3 && nbNodes != 4) || theEdgeNum > nbNodes )
577     return false;
578
579   vector<int> anIds( nbNodes );
580   SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
581   int i = 0;
582   while( anIter->more() )
583     anIds[ i++ ] = anIter->next()->GetID();
584
585   if ( theEdgeNum < nbNodes - 1 )
586   {
587     theNodeId1 = anIds[ theEdgeNum ];
588     theNodeId2 = anIds[ theEdgeNum + 1 ];
589   }
590   else
591   {
592     theNodeId1 = anIds[ nbNodes - 1 ];
593     theNodeId2 = anIds[ 0 ];
594   }
595
596   return true;
597 }
598
599 vtkUnstructuredGrid* SMESH_VisualObjDef::GetUnstructuredGrid()
600 {
601   if ( !myLocalGrid && !GetMesh()->isCompacted() )
602   {
603     GetMesh()->compactMesh();
604         updateEntitiesFlags();
605     vtkUnstructuredGrid *theGrid = GetMesh()->getGrid();
606     myGrid->ShallowCopy(theGrid);
607   }
608   return myGrid;
609 }
610
611
612 //=================================================================================
613 // function : IsValid
614 // purpose  : Return true if there are some entities
615 //=================================================================================
616 bool SMESH_VisualObjDef::IsValid() const
617 {
618         //MESSAGE("SMESH_VisualObjDef::IsValid");
619   return GetNbEntities(SMDSAbs_Node) > 0      || 
620          GetNbEntities(SMDSAbs_0DElement) > 0 || 
621          GetNbEntities(SMDSAbs_Edge) > 0      || 
622          GetNbEntities(SMDSAbs_Face) > 0      ||
623          GetNbEntities(SMDSAbs_Volume) > 0 ;
624 }
625
626 //=================================================================================
627 // function : updateEntitiesFlags
628 // purpose  : Update entities flags
629 //=================================================================================
630 void SMESH_VisualObjDef::updateEntitiesFlags() {
631
632         unsigned int tmp = myEntitiesState;
633         ClearEntitiesFlags();
634
635         map<SMDSAbs_ElementType,int> entities = SMESH::GetEntitiesFromObject(this);
636         
637
638         if( myEntitiesCache[SMDSAbs_0DElement] != 0 ||  myEntitiesCache[SMDSAbs_0DElement] >= entities[SMDSAbs_0DElement] )
639                 myEntitiesState &= ~SMESH_Actor::e0DElements;
640
641         if( myEntitiesCache[SMDSAbs_Edge] != 0 || myEntitiesCache[SMDSAbs_Edge] >= entities[SMDSAbs_Edge] )
642                 myEntitiesState &= ~SMESH_Actor::eEdges; 
643
644         if( myEntitiesCache[SMDSAbs_Face] != 0 || myEntitiesCache[SMDSAbs_Face] >= entities[SMDSAbs_Face] )
645                 myEntitiesState &= ~SMESH_Actor::eFaces; 
646
647         if( myEntitiesCache[SMDSAbs_Volume] != 0 || myEntitiesCache[SMDSAbs_Volume] >= entities[SMDSAbs_Volume] )
648                 myEntitiesState &= ~SMESH_Actor::eVolumes;
649
650         if( tmp != myEntitiesState ) {
651                 myEntitiesFlag = true;
652         }
653         
654         myEntitiesCache = entities;
655 }
656
657 //=================================================================================
658 // function : ClearEntitiesFlags
659 // purpose  : Clear the entities flags
660 //=================================================================================
661 void SMESH_VisualObjDef::ClearEntitiesFlags() {
662         myEntitiesState = SMESH_Actor::eAllEntity;
663         myEntitiesFlag = false;
664 }
665
666 //=================================================================================
667 // function : GetEntitiesFlag
668 // purpose  : Return the entities flag
669 //=================================================================================
670 bool SMESH_VisualObjDef::GetEntitiesFlag() {
671         return myEntitiesFlag;
672 }
673
674 //=================================================================================
675 // function : GetEntitiesState
676 // purpose  : Return the entities state
677 //=================================================================================
678 unsigned int SMESH_VisualObjDef::GetEntitiesState() {
679         return myEntitiesState;
680 }
681
682 /*
683   Class       : SMESH_MeshObj
684   Description : Class for visualisation of mesh
685 */
686
687 //=================================================================================
688 // function : SMESH_MeshObj
689 // purpose  : Constructor
690 //=================================================================================
691 SMESH_MeshObj::SMESH_MeshObj(SMESH::SMESH_Mesh_ptr theMesh):
692   myClient(SalomeApp_Application::orb(),theMesh)
693 {
694         myEmptyGrid = 0;
695   if ( MYDEBUG ) 
696     MESSAGE("SMESH_MeshObj - this = "<<this<<"; theMesh->_is_nil() = "<<theMesh->_is_nil());
697 }
698
699 //=================================================================================
700 // function : ~SMESH_MeshObj
701 // purpose  : Destructor
702 //=================================================================================
703 SMESH_MeshObj::~SMESH_MeshObj()
704 {
705   if ( MYDEBUG ) 
706     MESSAGE("SMESH_MeshObj - this = "<<this<<"\n");
707 }
708
709 //=================================================================================
710 // function : Update
711 // purpose  : Update mesh and fill grid with new values if necessary 
712 //=================================================================================
713 bool SMESH_MeshObj::Update( int theIsClear )
714 {
715   // Update SMDS_Mesh on client part
716   MESSAGE("SMESH_MeshObj::Update " << this);
717   if ( myClient.Update(theIsClear) || GetUnstructuredGrid()->GetNumberOfPoints()==0) {
718     MESSAGE("buildPrs");
719     buildPrs();  // Fill unstructured grid
720     return true;
721   }
722   return false;
723 }
724
725 bool SMESH_MeshObj::NulData()
726 {
727         MESSAGE ("SMESH_MeshObj::NulData() ==================================================================================");
728         if (!myEmptyGrid)
729         {
730           myEmptyGrid = SMDS_UnstructuredGrid::New();
731           myEmptyGrid->Initialize();
732           myEmptyGrid->Allocate();
733           vtkPoints* points = vtkPoints::New();
734           points->SetNumberOfPoints(0);
735           myEmptyGrid->SetPoints( points );
736           points->Delete();
737           myEmptyGrid->BuildLinks();
738         }
739         myGrid->ShallowCopy(myEmptyGrid);
740         return true;
741 }
742 //=================================================================================
743 // function : GetElemDimension
744 // purpose  : Get dimension of element
745 //=================================================================================
746 int SMESH_MeshObj::GetElemDimension( const int theObjId )
747 {
748   const SMDS_MeshElement* anElem = myClient->FindElement( theObjId );
749   if ( anElem == 0 )
750     return 0;
751
752   int aType = anElem->GetType();
753   switch ( aType )
754   {
755     case SMDSAbs_0DElement : return 0;
756     case SMDSAbs_Edge  : return 1;
757     case SMDSAbs_Face  : return 2;
758     case SMDSAbs_Volume: return 3;
759     default            : return 0;
760   }
761 }
762
763 //=================================================================================
764 // function : GetEntities
765 // purpose  : Get entities of specified type. Return number of entities
766 //=================================================================================
767 int SMESH_MeshObj::GetNbEntities( const SMDSAbs_ElementType theType) const
768 {
769   switch ( theType )
770   {
771     case SMDSAbs_Node:
772     {
773       return myClient->NbNodes();
774     }
775     break;
776     case SMDSAbs_0DElement:
777     {
778       return myClient->Nb0DElements();
779     }
780     break;
781     case SMDSAbs_Edge:
782     {
783       return myClient->NbEdges();
784     }
785     break;
786     case SMDSAbs_Face:
787     {
788       return myClient->NbFaces();
789     }
790     break;
791     case SMDSAbs_Volume:
792     {
793       return myClient->NbVolumes();
794     }
795     break;
796     default:
797       return 0;
798     break;
799   }
800 }
801
802 int SMESH_MeshObj::GetEntities( const SMDSAbs_ElementType theType, TEntityList& theObjs ) const
803 {
804   theObjs.clear();
805
806   switch ( theType )
807   {
808     case SMDSAbs_Node:
809     {
810       SMDS_NodeIteratorPtr anIter = myClient->nodesIterator();
811       while ( anIter->more() ) theObjs.push_back( anIter->next() );
812     }
813     break;
814     case SMDSAbs_0DElement:
815     {
816       SMDS_0DElementIteratorPtr anIter = myClient->elements0dIterator();
817       while ( anIter->more() ) theObjs.push_back( anIter->next() );
818     }
819     break;
820     case SMDSAbs_Edge:
821     {
822       SMDS_EdgeIteratorPtr anIter = myClient->edgesIterator();
823       while ( anIter->more() ) theObjs.push_back( anIter->next() );
824     }
825     break;
826     case SMDSAbs_Face:
827     {
828       SMDS_FaceIteratorPtr anIter = myClient->facesIterator();
829       while ( anIter->more() ) theObjs.push_back( anIter->next() );
830     }
831     break;
832     case SMDSAbs_Volume:
833     {
834       SMDS_VolumeIteratorPtr anIter = myClient->volumesIterator();
835       while ( anIter->more() ) theObjs.push_back( anIter->next() );
836     }
837     break;
838     default:
839     break;
840   }
841
842   return theObjs.size();
843 }
844
845 //=================================================================================
846 // function : UpdateFunctor
847 // purpose  : Update functor in accordance with current mesh
848 //=================================================================================
849 void SMESH_MeshObj::UpdateFunctor( const SMESH::Controls::FunctorPtr& theFunctor )
850 {
851   theFunctor->SetMesh( GetMesh() );
852 }
853
854 //=================================================================================
855 // function : IsNodePrs
856 // purpose  : Return true if node presentation is used
857 //=================================================================================
858 bool SMESH_MeshObj::IsNodePrs() const
859 {
860   return myClient->Nb0DElements() == 0 && myClient->NbEdges() == 0 && myClient->NbFaces() == 0 && myClient->NbVolumes() == 0 ;
861 }
862
863
864 /*
865   Class       : SMESH_SubMeshObj
866   Description : Base class for visualisation of submeshes and groups
867 */
868
869 //=================================================================================
870 // function : SMESH_SubMeshObj
871 // purpose  : Constructor
872 //=================================================================================
873 SMESH_SubMeshObj::SMESH_SubMeshObj( SMESH_MeshObj* theMeshObj )
874 {
875   if ( MYDEBUG ) MESSAGE( "SMESH_SubMeshObj - theMeshObj = " << theMeshObj );
876   
877   myMeshObj = theMeshObj;
878 }
879
880 SMESH_SubMeshObj::~SMESH_SubMeshObj()
881 {
882 }
883
884 //=================================================================================
885 // function : GetElemDimension
886 // purpose  : Get dimension of element
887 //=================================================================================
888 int SMESH_SubMeshObj::GetElemDimension( const int theObjId )
889 {
890   return myMeshObj == 0 ? 0 : myMeshObj->GetElemDimension( theObjId );
891 }
892
893 //=================================================================================
894 // function : UpdateFunctor
895 // purpose  : Update functor in accordance with current mesh
896 //=================================================================================
897 void SMESH_SubMeshObj::UpdateFunctor( const SMESH::Controls::FunctorPtr& theFunctor )
898 {
899   theFunctor->SetMesh( myMeshObj->GetMesh() );
900 }
901
902 //=================================================================================
903 // function : Update
904 // purpose  : Update mesh object and fill grid with new values 
905 //=================================================================================
906 bool SMESH_SubMeshObj::Update( int theIsClear )
907 {
908         MESSAGE("SMESH_SubMeshObj::Update " << this)
909   bool changed = myMeshObj->Update( theIsClear );
910   buildPrs(true);
911   return changed;
912 }
913
914
915 /*
916   Class       : SMESH_GroupObj
917   Description : Class for visualisation of groups
918 */
919
920 //=================================================================================
921 // function : SMESH_GroupObj
922 // purpose  : Constructor
923 //=================================================================================
924 SMESH_GroupObj::SMESH_GroupObj( SMESH::SMESH_GroupBase_ptr theGroup, 
925                                 SMESH_MeshObj*             theMeshObj )
926 : SMESH_SubMeshObj( theMeshObj ),
927   myGroupServer( SMESH::SMESH_GroupBase::_duplicate(theGroup) )
928 {
929   if ( MYDEBUG ) MESSAGE("SMESH_GroupObj - theGroup->_is_nil() = "<<theGroup->_is_nil());
930   myGroupServer->Register();
931 }
932
933 SMESH_GroupObj::~SMESH_GroupObj()
934 {
935   if ( MYDEBUG ) MESSAGE("~SMESH_GroupObj");
936   myGroupServer->UnRegister();
937 }
938
939 //=================================================================================
940 // function : IsNodePrs
941 // purpose  : Return true if node presentation is used
942 //=================================================================================
943 bool SMESH_GroupObj::IsNodePrs() const
944 {
945   return myGroupServer->GetType() == SMESH::NODE;
946 }
947
948 //=================================================================================
949 // function : GetElementType
950 // purpose  : Return type of elements of group
951 //=================================================================================
952 SMDSAbs_ElementType SMESH_GroupObj::GetElementType() const
953 {
954   return SMDSAbs_ElementType(myGroupServer->GetType());
955 }
956
957 //=================================================================================
958 // function : getNodesFromElems
959 // purpose  : Retrieve nodes from elements
960 //=================================================================================
961 static int getNodesFromElems( SMESH::long_array_var&              theElemIds,
962                               const SMDS_Mesh*                    theMesh,
963                               std::list<const SMDS_MeshElement*>& theResList )
964 {
965   set<const SMDS_MeshElement*> aNodeSet;
966
967   for ( CORBA::Long i = 0, n = theElemIds->length(); i < n; i++ )
968   {
969     const SMDS_MeshElement* anElem = theMesh->FindElement( theElemIds[ i ] );
970     if ( anElem != 0 )
971     {
972       SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
973       while ( anIter->more() )
974       {
975         const SMDS_MeshElement* aNode = anIter->next();
976         if ( aNode != 0 )
977           aNodeSet.insert( aNode );
978       }
979     }
980   }
981
982   set<const SMDS_MeshElement*>::const_iterator anIter;
983   for ( anIter = aNodeSet.begin(); anIter != aNodeSet.end(); ++anIter )
984     theResList.push_back( *anIter );
985
986   return theResList.size();    
987 }
988
989 //=================================================================================
990 // function : getPointers
991 // purpose  : Get std::list<const SMDS_MeshElement*> from list of IDs
992 //=================================================================================
993 static int getPointers( const SMDSAbs_ElementType            theRequestType,
994                         SMESH::long_array_var&              theElemIds,
995                         const SMDS_Mesh*                    theMesh,
996                         std::list<const SMDS_MeshElement*>& theResList )
997 {
998   for ( CORBA::Long i = 0, n = theElemIds->length(); i < n; i++ )
999   {
1000     const SMDS_MeshElement* anElem = theRequestType == SMDSAbs_Node
1001       ? theMesh->FindNode( theElemIds[ i ] ) : theMesh->FindElement( theElemIds[ i ] );
1002
1003     if ( anElem != 0 )
1004       theResList.push_back( anElem );
1005   }
1006
1007   return theResList.size();
1008 }
1009
1010
1011 //=================================================================================
1012 // function : GetEntities
1013 // purpose  : Get entities of specified type. Return number of entities
1014 //=================================================================================
1015 int SMESH_GroupObj::GetNbEntities( const SMDSAbs_ElementType theType) const
1016 {
1017   if(SMDSAbs_ElementType(myGroupServer->GetType()) == theType){
1018     return myGroupServer->Size();
1019   }
1020   return 0;
1021 }
1022
1023 int SMESH_GroupObj::GetEntities( const SMDSAbs_ElementType theType, TEntityList& theResList ) const
1024 {
1025   theResList.clear();
1026   SMDS_Mesh* aMesh = myMeshObj->GetMesh();
1027   
1028   if ( myGroupServer->Size() == 0 || aMesh == 0 )
1029     return 0;
1030
1031   SMDSAbs_ElementType aGrpType = SMDSAbs_ElementType(myGroupServer->GetType());
1032   SMESH::long_array_var anIds = myGroupServer->GetListOfID();
1033
1034   if ( aGrpType == theType )
1035     return getPointers( theType, anIds, aMesh, theResList );
1036   else if ( theType == SMDSAbs_Node )
1037     return getNodesFromElems( anIds, aMesh, theResList );
1038   else
1039     return 0;
1040 }    
1041
1042
1043
1044 /*
1045   Class       : SMESH_subMeshObj
1046   Description : Class for visualisation of submeshes
1047 */
1048
1049 //=================================================================================
1050 // function : SMESH_subMeshObj
1051 // purpose  : Constructor
1052 //=================================================================================
1053 SMESH_subMeshObj::SMESH_subMeshObj( SMESH::SMESH_subMesh_ptr theSubMesh,
1054                                     SMESH_MeshObj*           theMeshObj )
1055 : SMESH_SubMeshObj( theMeshObj ),
1056   mySubMeshServer( SMESH::SMESH_subMesh::_duplicate( theSubMesh ) )
1057 {
1058   if ( MYDEBUG ) MESSAGE( "SMESH_subMeshObj - theSubMesh->_is_nil() = " << theSubMesh->_is_nil() );
1059   
1060   mySubMeshServer->Register();
1061 }
1062
1063 SMESH_subMeshObj::~SMESH_subMeshObj()
1064 {
1065   if ( MYDEBUG ) MESSAGE( "~SMESH_subMeshObj" );
1066   mySubMeshServer->UnRegister();
1067 }
1068
1069 //=================================================================================
1070 // function : GetEntities
1071 // purpose  : Get entities of specified type. Return number of entities
1072 //=================================================================================
1073 int SMESH_subMeshObj::GetNbEntities( const SMDSAbs_ElementType theType) const
1074 {
1075   switch ( theType )
1076   {
1077     case SMDSAbs_Node:
1078     {
1079       return mySubMeshServer->GetNumberOfNodes( false );
1080     }
1081     break;
1082     case SMDSAbs_0DElement:
1083     case SMDSAbs_Edge:
1084     case SMDSAbs_Face:
1085     case SMDSAbs_Volume:
1086     {
1087       SMESH::long_array_var anIds = 
1088         mySubMeshServer->GetElementsByType( SMESH::ElementType(theType) );
1089       return anIds->length();
1090     }
1091     default:
1092       return 0;
1093     break;
1094   }
1095 }
1096
1097 int SMESH_subMeshObj::GetEntities( const SMDSAbs_ElementType theType, TEntityList& theResList ) const
1098 {
1099   theResList.clear();
1100
1101   SMDS_Mesh* aMesh = myMeshObj->GetMesh();
1102   if ( aMesh == 0 )
1103     return 0;
1104
1105   bool isNodal = IsNodePrs();
1106
1107   if ( isNodal )
1108   {
1109     if ( theType == SMDSAbs_Node )
1110     {
1111       SMESH::long_array_var anIds = mySubMeshServer->GetNodesId();
1112       return getPointers( SMDSAbs_Node, anIds, aMesh, theResList );
1113     }
1114   }
1115   else
1116   {
1117     if ( theType == SMDSAbs_Node )
1118     {
1119       SMESH::long_array_var anIds = mySubMeshServer->GetElementsId();
1120       return getNodesFromElems( anIds, aMesh, theResList );
1121     }
1122     else
1123     {
1124       SMESH::long_array_var anIds = 
1125         mySubMeshServer->GetElementsByType( SMESH::ElementType(theType) );
1126       return getPointers( theType, anIds, aMesh, theResList );
1127     }
1128   }
1129
1130   return 0;
1131 }
1132
1133 //=================================================================================
1134 // function : IsNodePrs
1135 // purpose  : Return true if node presentation is used
1136 //=================================================================================
1137 bool SMESH_subMeshObj::IsNodePrs() const
1138 {
1139   return mySubMeshServer->GetNumberOfElements() == 0;
1140 }