1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkInteractorStyleRubberBandZoom.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 #include "vtkInteractorStyleRubberBandZoom.h"
16 
17 #include "vtkCamera.h"
18 #include "vtkObjectFactory.h"
19 #include "vtkRenderer.h"
20 #include "vtkRenderWindow.h"
21 #include "vtkRenderWindowInteractor.h"
22 #include "vtkUnsignedCharArray.h"
23 
24 vtkStandardNewMacro(vtkInteractorStyleRubberBandZoom);
25 
vtkInteractorStyleRubberBandZoom()26 vtkInteractorStyleRubberBandZoom::vtkInteractorStyleRubberBandZoom()
27 {
28   this->StartPosition[0] = this->StartPosition[1] = 0;
29   this->EndPosition[0] = this->EndPosition[1] = 0;
30   this->Moving = 0;
31   this->PixelArray = vtkUnsignedCharArray::New();
32 }
33 
~vtkInteractorStyleRubberBandZoom()34 vtkInteractorStyleRubberBandZoom::~vtkInteractorStyleRubberBandZoom()
35 {
36   this->PixelArray->Delete();
37 }
38 
OnMouseMove()39 void vtkInteractorStyleRubberBandZoom::OnMouseMove()
40 {
41   if (!this->Interactor || !this->Moving)
42     {
43     return;
44     }
45 
46   this->EndPosition[0] = this->Interactor->GetEventPosition()[0];
47   this->EndPosition[1] = this->Interactor->GetEventPosition()[1];
48   int *size = this->Interactor->GetRenderWindow()->GetSize();
49   if (this->EndPosition[0] > (size[0]-1))
50     {
51     this->EndPosition[0] = size[0]-1;
52     }
53   if (this->EndPosition[0] < 0)
54     {
55     this->EndPosition[0] = 0;
56     }
57   if (this->EndPosition[1] > (size[1]-1))
58     {
59     this->EndPosition[1] = size[1]-1;
60     }
61   if (this->EndPosition[1] < 0)
62     {
63     this->EndPosition[1] = 0;
64     }
65 
66   vtkUnsignedCharArray *tmpPixelArray = vtkUnsignedCharArray::New();
67   tmpPixelArray->DeepCopy(this->PixelArray);
68 
69   unsigned char *pixels = tmpPixelArray->GetPointer(0);
70 
71   int min[2], max[2];
72   min[0] = this->StartPosition[0] <= this->EndPosition[0] ?
73     this->StartPosition[0] : this->EndPosition[0];
74   min[1] = this->StartPosition[1] <= this->EndPosition[1] ?
75     this->StartPosition[1] : this->EndPosition[1];
76   max[0] = this->EndPosition[0] > this->StartPosition[0] ?
77     this->EndPosition[0] : this->StartPosition[0];
78   max[1] = this->EndPosition[1] > this->StartPosition[1] ?
79     this->EndPosition[1] : this->StartPosition[1];
80 
81   int i;
82   for (i = min[0]; i <= max[0]; i++)
83     {
84     pixels[3*(min[1]*size[0]+i)] = 255 ^ pixels[3*(min[1]*size[0]+i)];
85     pixels[3*(min[1]*size[0]+i)+1] = 255 ^ pixels[3*(min[1]*size[0]+i)+1];
86     pixels[3*(min[1]*size[0]+i)+2] = 255 ^ pixels[3*(min[1]*size[0]+i)+2];
87     pixels[3*(max[1]*size[0]+i)] = 255 ^ pixels[3*(max[1]*size[0]+i)];
88     pixels[3*(max[1]*size[0]+i)+1] = 255 ^ pixels[3*(max[1]*size[0]+i)+1];
89     pixels[3*(max[1]*size[0]+i)+2] = 255 ^ pixels[3*(max[1]*size[0]+i)+2];
90     }
91   for (i = min[1]+1; i < max[1]; i++)
92     {
93     pixels[3*(i*size[0]+min[0])] = 255 ^ pixels[3*(i*size[0]+min[0])];
94     pixels[3*(i*size[0]+min[0])+1] = 255 ^ pixels[3*(i*size[0]+min[0])+1];
95     pixels[3*(i*size[0]+min[0])+2] = 255 ^ pixels[3*(i*size[0]+min[0])+2];
96     pixels[3*(i*size[0]+max[0])] = 255 ^ pixels[3*(i*size[0]+max[0])];
97     pixels[3*(i*size[0]+max[0])+1] = 255 ^ pixels[3*(i*size[0]+max[0])+1];
98     pixels[3*(i*size[0]+max[0])+2] = 255 ^ pixels[3*(i*size[0]+max[0])+2];
99     }
100 
101   this->Interactor->GetRenderWindow()->SetPixelData(0, 0, size[0]-1, size[1]-1, pixels, 1);
102 
103   tmpPixelArray->Delete();
104 }
105 
OnLeftButtonDown()106 void vtkInteractorStyleRubberBandZoom::OnLeftButtonDown()
107 {
108   if (!this->Interactor)
109     {
110     return;
111     }
112   this->Moving = 1;
113 
114   vtkRenderWindow *renWin = this->Interactor->GetRenderWindow();
115 
116   this->StartPosition[0] = this->Interactor->GetEventPosition()[0];
117   this->StartPosition[1] = this->Interactor->GetEventPosition()[1];
118   this->EndPosition[0] = this->StartPosition[0];
119   this->EndPosition[1] = this->StartPosition[1];
120 
121   this->PixelArray->Initialize();
122   this->PixelArray->SetNumberOfComponents(3);
123   int *size = renWin->GetSize();
124   this->PixelArray->SetNumberOfTuples(size[0]*size[1]);
125 
126   renWin->GetPixelData(0, 0, size[0]-1, size[1]-1, 1, this->PixelArray);
127 
128   this->FindPokedRenderer(this->StartPosition[0], this->StartPosition[1]);
129 }
130 
OnLeftButtonUp()131 void vtkInteractorStyleRubberBandZoom::OnLeftButtonUp()
132 {
133   if (!this->Interactor || !this->Moving)
134     {
135     return;
136     }
137 
138   if (   (this->StartPosition[0] != this->EndPosition[0])
139       || (this->StartPosition[1] != this->EndPosition[1]) )
140     {
141     this->Zoom();
142     }
143   this->Moving = 0;
144 }
145 
Zoom()146 void vtkInteractorStyleRubberBandZoom::Zoom()
147 {
148   int width, height;
149   width = abs(this->EndPosition[0] - this->StartPosition[0]);
150   height = abs(this->EndPosition[1] - this->StartPosition[1]);
151   int *size = this->CurrentRenderer->GetSize();
152   int *origin = this->CurrentRenderer->GetOrigin();
153   vtkCamera *cam = this->CurrentRenderer->GetActiveCamera();
154 
155   int min[2];
156   double rbcenter[3];
157   min[0] = this->StartPosition[0] < this->EndPosition[0] ?
158     this->StartPosition[0] : this->EndPosition[0];
159   min[1] = this->StartPosition[1] < this->EndPosition[1] ?
160     this->StartPosition[1] : this->EndPosition[1];
161 
162   rbcenter[0] = min[0] + 0.5*width;
163   rbcenter[1] = min[1] + 0.5*height;
164   rbcenter[2] = 0;
165 
166   this->CurrentRenderer->SetDisplayPoint(rbcenter);
167   this->CurrentRenderer->DisplayToView();
168   this->CurrentRenderer->ViewToWorld();
169 
170   double invw;
171   double worldRBCenter[4];
172   this->CurrentRenderer->GetWorldPoint(worldRBCenter);
173   invw = 1.0/worldRBCenter[3];
174   worldRBCenter[0] *= invw;
175   worldRBCenter[1] *= invw;
176   worldRBCenter[2] *= invw;
177 
178   double winCenter[3];
179   winCenter[0] = origin[0] + 0.5*size[0];
180   winCenter[1] = origin[1] + 0.5*size[1];
181   winCenter[2] = 0;
182 
183   this->CurrentRenderer->SetDisplayPoint(winCenter);
184   this->CurrentRenderer->DisplayToView();
185   this->CurrentRenderer->ViewToWorld();
186 
187   double worldWinCenter[4];
188   this->CurrentRenderer->GetWorldPoint(worldWinCenter);
189   invw = 1.0/worldWinCenter[3];
190   worldWinCenter[0] *= invw;
191   worldWinCenter[1] *= invw;
192   worldWinCenter[2] *= invw;
193 
194   double translation[3];
195   translation[0] = worldRBCenter[0] - worldWinCenter[0];
196   translation[1] = worldRBCenter[1] - worldWinCenter[1];
197   translation[2] = worldRBCenter[2] - worldWinCenter[2];
198 
199   double pos[3], fp[3];
200   cam->GetPosition(pos);
201   cam->GetFocalPoint(fp);
202 
203   pos[0] += translation[0]; pos[1] += translation[1]; pos[2] += translation[2];
204   fp[0] += translation[0];  fp[1] += translation[1];  fp[2] += translation[2];
205 
206   cam->SetPosition(pos);
207   cam->SetFocalPoint(fp);
208 
209   double zoomFactor;
210   if (width > height)
211     {
212     zoomFactor = size[0] / static_cast<double>(width);
213     }
214   else
215     {
216     zoomFactor = size[1] / static_cast<double>(height);
217     }
218   if (cam->GetParallelProjection())
219     {
220     cam->Zoom(zoomFactor);
221     }
222   else
223     {
224     // In perspective mode, zoom in by moving the camera closer.  Because we are
225     // moving the camera closer, we have to be careful to try to adjust the
226     // clipping planes to best match the actual position they were in before.
227     double initialDistance = cam->GetDistance();
228     cam->Dolly(zoomFactor);
229     double finalDistance = cam->GetDistance();
230     double deltaDistance = initialDistance - finalDistance;
231     double clippingRange[2];
232     cam->GetClippingRange(clippingRange);
233     clippingRange[0] -= deltaDistance;
234     clippingRange[1] -= deltaDistance;
235     // Correct bringing clipping planes too close or behind camera.
236     if (clippingRange[1] <= 0.0)
237       {
238       clippingRange[1] = 0.001;
239       }
240     // This near plane check comes from vtkRenderer::ResetCameraClippingRange()
241     if (clippingRange[0] < 0.001*clippingRange[1])
242       {
243       clippingRange[0] = 0.001*clippingRange[1];
244       }
245     cam->SetClippingRange(clippingRange);
246     }
247 
248   this->Interactor->Render();
249 }
250 
PrintSelf(ostream & os,vtkIndent indent)251 void vtkInteractorStyleRubberBandZoom::PrintSelf(ostream& os, vtkIndent indent)
252 {
253   this->Superclass::PrintSelf(os, indent);
254 }
255