Salome HOME
Update from BR_V5_DEV 13Feb2009
[modules/gui.git] / src / VTKViewer / VTKViewer_Utilities.cxx
1 //  Copyright (C) 2007-2008  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 #include "VTKViewer_Utilities.h"
23 #include "VTKViewer_Actor.h"
24
25 #include <algorithm>
26
27 // VTK Includes
28 #include <vtkMath.h>
29 #include <vtkCamera.h>
30 #include <vtkRenderer.h>
31 #include <vtkRenderWindow.h>
32
33 using namespace std;
34
35 /*!@see vtkRenderer::ResetCamera(vtkFloatingPointType bounds[6]) method*/
36 void 
37 ResetCamera(vtkRenderer* theRenderer, 
38             int theUsingZeroFocalPoint)
39 {  
40   if(!theRenderer)
41     return;
42
43   vtkCamera* aCamera = theRenderer->GetActiveCamera();
44   if(!aCamera) 
45     return;
46
47   vtkFloatingPointType aBounds[6];
48   int aCount = ComputeVisiblePropBounds(theRenderer,aBounds);
49
50   if(theUsingZeroFocalPoint || aCount){
51     static vtkFloatingPointType MIN_DISTANCE = 1.0 / VTK_LARGE_FLOAT;
52
53     vtkFloatingPointType aLength = aBounds[1]-aBounds[0];
54     aLength = max((aBounds[3]-aBounds[2]),aLength);
55     aLength = max((aBounds[5]-aBounds[4]),aLength);
56     
57     if(aLength < MIN_DISTANCE)
58       return;
59
60     vtkFloatingPointType aWidth = 
61       sqrt((aBounds[1]-aBounds[0])*(aBounds[1]-aBounds[0]) +
62            (aBounds[3]-aBounds[2])*(aBounds[3]-aBounds[2]) +
63            (aBounds[5]-aBounds[4])*(aBounds[5]-aBounds[4]));
64     
65     if(aWidth < MIN_DISTANCE)
66       return;
67
68     vtkFloatingPointType aViewPlaneNormal[3];
69     aCamera->GetViewPlaneNormal(aViewPlaneNormal);
70     
71     vtkFloatingPointType aCenter[3] = {0.0, 0.0, 0.0};
72     if(!theUsingZeroFocalPoint){
73       aCenter[0] = (aBounds[0] + aBounds[1])/2.0;
74       aCenter[1] = (aBounds[2] + aBounds[3])/2.0;
75       aCenter[2] = (aBounds[4] + aBounds[5])/2.0;
76     }
77     aCamera->SetFocalPoint(aCenter[0],aCenter[1],aCenter[2]);
78     
79     vtkFloatingPointType aViewAngle = aCamera->GetViewAngle();
80     vtkFloatingPointType aDistance = 2.0*aWidth/tan(aViewAngle*vtkMath::Pi()/360.0);
81     
82     // check view-up vector against view plane normal
83     vtkFloatingPointType aViewUp[3];
84     aCamera->GetViewUp(aViewUp);
85     if(fabs(vtkMath::Dot(aViewUp,aViewPlaneNormal)) > 0.999)
86       aCamera->SetViewUp(-aViewUp[2], aViewUp[0], aViewUp[1]);
87     
88     // update the camera
89     aCamera->SetPosition(aCenter[0]+aDistance*aViewPlaneNormal[0],
90                          aCenter[1]+aDistance*aViewPlaneNormal[1],
91                          aCenter[2]+aDistance*aViewPlaneNormal[2]);
92
93     // find size of the window
94     int* aWinSize = theRenderer->GetSize();
95     if(aWinSize[0] < aWinSize[1]) 
96       aWidth *= vtkFloatingPointType(aWinSize[1])/vtkFloatingPointType(aWinSize[0]);
97     
98     if(theUsingZeroFocalPoint) 
99       aWidth *= sqrt(2.0);
100     
101     aCamera->SetParallelScale(aWidth/2.0);
102   }
103
104   ResetCameraClippingRange(theRenderer);
105 }
106
107 /*! Compute the bounds of the visible props*/
108 int
109 ComputeVisiblePropBounds(vtkRenderer* theRenderer, 
110                          vtkFloatingPointType theBounds[6])
111 {
112   int aCount = 0;
113   
114   theBounds[0] = theBounds[2] = theBounds[4] = VTK_LARGE_FLOAT;
115   theBounds[1] = theBounds[3] = theBounds[5] = -VTK_LARGE_FLOAT;
116   
117   // loop through all props
118   vtkActorCollection* aCollection = theRenderer->GetActors();
119   aCollection->InitTraversal();
120   while (vtkActor* aProp = aCollection->GetNextActor()) {
121     // if it's invisible, or has no geometry, we can skip the rest 
122     if(aProp->GetVisibility() && aProp->GetMapper()){
123       if(VTKViewer_Actor* anActor = VTKViewer_Actor::SafeDownCast(aProp))
124         if(anActor->IsInfinitive())
125           continue;
126         
127       vtkFloatingPointType *aBounds = aProp->GetBounds();
128       static vtkFloatingPointType MAX_DISTANCE = 0.9*VTK_LARGE_FLOAT;
129       // make sure we haven't got bogus bounds
130       if ( aBounds != NULL &&
131            aBounds[0] > -MAX_DISTANCE && aBounds[1] < MAX_DISTANCE &&
132            aBounds[2] > -MAX_DISTANCE && aBounds[3] < MAX_DISTANCE &&
133            aBounds[4] > -MAX_DISTANCE && aBounds[5] < MAX_DISTANCE )
134       {
135         aCount++;
136
137         theBounds[0] = min(aBounds[0],theBounds[0]);
138         theBounds[2] = min(aBounds[2],theBounds[2]);
139         theBounds[4] = min(aBounds[4],theBounds[4]);
140
141         theBounds[1] = max(aBounds[1],theBounds[1]);
142         theBounds[3] = max(aBounds[3],theBounds[3]);
143         theBounds[5] = max(aBounds[5],theBounds[5]);
144
145       }//not bogus
146     }
147   }
148   return aCount;
149 }
150
151 /*!@see vtkRenderer::ResetCameraClippingRange(vtkFloatingPointType bounds[6]) method*/
152 void
153 ResetCameraClippingRange(vtkRenderer* theRenderer)
154 {
155   if(!theRenderer || !theRenderer->VisibleActorCount()) return;
156   
157   vtkCamera* anActiveCamera = theRenderer->GetActiveCamera();
158   if( anActiveCamera == NULL ){
159     return;
160   }
161   
162   // Find the plane equation for the camera view plane
163   vtkFloatingPointType vn[3];
164   anActiveCamera->GetViewPlaneNormal(vn);
165   vtkFloatingPointType  position[3];
166   anActiveCamera->GetPosition(position);
167   
168   vtkFloatingPointType bounds[6];
169   theRenderer->ComputeVisiblePropBounds(bounds);
170   
171   vtkFloatingPointType center[3];
172   center[0] = (bounds[0] + bounds[1])/2.0;
173   center[1] = (bounds[2] + bounds[3])/2.0;
174   center[2] = (bounds[4] + bounds[5])/2.0;
175   
176   vtkFloatingPointType width = sqrt((bounds[1]-bounds[0])*(bounds[1]-bounds[0]) +
177     (bounds[3]-bounds[2])*(bounds[3]-bounds[2]) +
178     (bounds[5]-bounds[4])*(bounds[5]-bounds[4]));
179   
180   vtkFloatingPointType distance = sqrt((position[0]-center[0])*(position[0]-center[0]) +
181        (position[1]-center[1])*(position[1]-center[1]) +
182        (position[2]-center[2])*(position[2]-center[2]));
183   
184   vtkFloatingPointType range[2] = {distance - width/2.0, distance + width/2.0};
185   
186   // Do not let the range behind the camera throw off the calculation.
187   if (range[0] < 0.0) range[0] = 0.0;
188   
189   anActiveCamera->SetClippingRange( range );
190 }
191
192 /*!Compute trihedron size.*/
193 bool
194 ComputeTrihedronSize( vtkRenderer* theRenderer,
195                       vtkFloatingPointType& theNewSize,
196                       const vtkFloatingPointType theSize, 
197                       const vtkFloatingPointType theSizeInPercents )
198 {
199   // calculating diagonal of visible props of the renderer
200   vtkFloatingPointType bnd[ 6 ];
201   if ( ComputeVisiblePropBounds( theRenderer, bnd ) == 0 )
202   {
203     bnd[ 1 ] = bnd[ 3 ] = bnd[ 5 ] = 100;
204     bnd[ 0 ] = bnd[ 2 ] = bnd[ 4 ] = 0;
205   }
206   vtkFloatingPointType aLength = 0;
207
208   aLength = bnd[ 1 ]-bnd[ 0 ];
209   aLength = max( ( bnd[ 3 ] - bnd[ 2 ] ),aLength );
210   aLength = max( ( bnd[ 5 ] - bnd[ 4 ] ),aLength );
211
212   static vtkFloatingPointType EPS_SIZE = 5.0E-3;
213   theNewSize = aLength * theSizeInPercents / 100.0;
214
215   // if the new trihedron size have sufficient difference, then apply the value
216   return fabs( theNewSize - theSize) > theSize * EPS_SIZE ||
217          fabs( theNewSize-theSize ) > theNewSize * EPS_SIZE;
218 }
219
220 bool IsBBEmpty(vtkRenderer* theRenderer)
221 {
222   if(!theRenderer)
223     return false;
224
225   vtkFloatingPointType aNewBndBox[6];
226   aNewBndBox[ 0 ] = aNewBndBox[ 2 ] = aNewBndBox[ 4 ] = VTK_LARGE_FLOAT;
227   aNewBndBox[ 1 ] = aNewBndBox[ 3 ] = aNewBndBox[ 5 ] = -VTK_LARGE_FLOAT;
228   
229   // iterate through displayed objects and set size if necessary
230   vtkActorCollection* anActors = theRenderer->GetActors();
231   anActors->InitTraversal();
232   bool isAny = false;
233   while(vtkActor* anAct = anActors->GetNextActor())
234     //if(SALOME_Actor* anActor = dynamic_cast<SALOME_Actor*>(anAct))
235     if(VTKViewer_Actor* anActor = VTKViewer_Actor::SafeDownCast(anAct))
236       if(anActor->GetVisibility() && !anActor->IsInfinitive())
237       {
238         vtkFloatingPointType *aBounds = anActor->GetBounds();
239         if(aBounds[0] > -VTK_LARGE_FLOAT && aBounds[1] < VTK_LARGE_FLOAT &&
240            aBounds[2] > -VTK_LARGE_FLOAT && aBounds[3] < VTK_LARGE_FLOAT &&
241            aBounds[4] > -VTK_LARGE_FLOAT && aBounds[5] < VTK_LARGE_FLOAT)
242           isAny = true;
243       }
244   
245   return !isAny;
246 }
247
248 bool ComputeBBCenter(vtkRenderer* theRenderer, vtkFloatingPointType theCenter[3])
249 {  
250   theCenter[0] = theCenter[1] = theCenter[2] = 0.0;
251   
252   if(!theRenderer)
253     return false;
254
255   vtkFloatingPointType aNewBndBox[6];
256   aNewBndBox[ 0 ] = aNewBndBox[ 2 ] = aNewBndBox[ 4 ] = VTK_LARGE_FLOAT;
257   aNewBndBox[ 1 ] = aNewBndBox[ 3 ] = aNewBndBox[ 5 ] = -VTK_LARGE_FLOAT;
258
259   // iterate through displayed objects and set size if necessary
260   vtkActorCollection* anActors = theRenderer->GetActors();
261   anActors->InitTraversal();
262   bool isAny = false;
263   while(vtkActor* anAct = anActors->GetNextActor())
264   {
265     //if(SALOME_Actor* anActor = dynamic_cast<SALOME_Actor*>(anAct))
266     if(VTKViewer_Actor* anActor = VTKViewer_Actor::SafeDownCast(anAct))
267     {
268       if(anActor->GetVisibility() && !anActor->IsInfinitive())
269       {
270         vtkFloatingPointType *aBounds = anActor->GetBounds();
271         if(aBounds[0] > -VTK_LARGE_FLOAT && aBounds[1] < VTK_LARGE_FLOAT &&
272            aBounds[2] > -VTK_LARGE_FLOAT && aBounds[3] < VTK_LARGE_FLOAT &&
273            aBounds[4] > -VTK_LARGE_FLOAT && aBounds[5] < VTK_LARGE_FLOAT)
274         {
275           for(int i = 0; i < 5; i = i + 2){
276             if(aBounds[i] < aNewBndBox[i]) 
277               aNewBndBox[i] = aBounds[i];
278             if(aBounds[i+1] > aNewBndBox[i+1]) 
279               aNewBndBox[i+1] = aBounds[i+1];
280           }
281           isAny = true;
282         }
283       }
284     }
285   }
286   
287   if ( !isAny )
288   {
289     // null bounding box => the center is (0,0,0)
290     return true;
291   }
292
293   if(aNewBndBox[0] > -VTK_LARGE_FLOAT && aNewBndBox[1] < VTK_LARGE_FLOAT &&
294      aNewBndBox[2] > -VTK_LARGE_FLOAT && aNewBndBox[3] < VTK_LARGE_FLOAT &&
295      aNewBndBox[4] > -VTK_LARGE_FLOAT && aNewBndBox[5] < VTK_LARGE_FLOAT)
296   {
297     static vtkFloatingPointType MIN_DISTANCE = 1.0 / VTK_LARGE_FLOAT;
298     
299     vtkFloatingPointType aLength = aNewBndBox[1]-aNewBndBox[0];
300     aLength = max((aNewBndBox[3]-aNewBndBox[2]),aLength);
301     aLength = max((aNewBndBox[5]-aNewBndBox[4]),aLength);
302     
303     if(aLength < MIN_DISTANCE)
304       return false;
305
306     vtkFloatingPointType aWidth = 
307       sqrt((aNewBndBox[1]-aNewBndBox[0])*(aNewBndBox[1]-aNewBndBox[0]) +
308            (aNewBndBox[3]-aNewBndBox[2])*(aNewBndBox[3]-aNewBndBox[2]) +
309            (aNewBndBox[5]-aNewBndBox[4])*(aNewBndBox[5]-aNewBndBox[4]));
310     
311     if(aWidth < MIN_DISTANCE)
312       return false;
313
314     theCenter[0] = (aNewBndBox[0] + aNewBndBox[1])/2.0;
315     theCenter[1] = (aNewBndBox[2] + aNewBndBox[3])/2.0;
316     theCenter[2] = (aNewBndBox[4] + aNewBndBox[5])/2.0;
317     return true;
318   }
319
320   return false;
321
322   /*
323   vtkFloatingPointType aBounds[6];
324   int aCount = ComputeVisiblePropBounds(theRenderer,aBounds);
325   printf("aNewBndBox[0] = %f, aNewBndBox[1] = %f,\naNewBndBox[2] = %f, aNewBndBox[3] = %f,\naNewBndBox[4] = %f, aNewBndBox[5] = %f\n",
326            aBounds[0],aBounds[1],aBounds[2],aBounds[3],aBounds[4],aBounds[5]);
327   printf("aCount = %d\n",aCount);
328
329   if(aCount){
330     static vtkFloatingPointType MIN_DISTANCE = 1.0 / VTK_LARGE_FLOAT;
331
332     vtkFloatingPointType aLength = aBounds[1]-aBounds[0];
333     aLength = max((aBounds[3]-aBounds[2]),aLength);
334     aLength = max((aBounds[5]-aBounds[4]),aLength);
335     
336     if(aLength < MIN_DISTANCE)
337       return false;
338
339     vtkFloatingPointType aWidth = 
340       sqrt((aBounds[1]-aBounds[0])*(aBounds[1]-aBounds[0]) +
341            (aBounds[3]-aBounds[2])*(aBounds[3]-aBounds[2]) +
342            (aBounds[5]-aBounds[4])*(aBounds[5]-aBounds[4]));
343     
344     if(aWidth < MIN_DISTANCE)
345       return false;
346
347     theCenter[0] = (aBounds[0] + aBounds[1])/2.0;
348     theCenter[1] = (aBounds[2] + aBounds[3])/2.0;
349     theCenter[2] = (aBounds[4] + aBounds[5])/2.0;
350     return true;
351   }
352   return false;*/
353 }