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