1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkInteractorStyleRubberBand2D.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 /*-------------------------------------------------------------------------
16   Copyright 2008 Sandia Corporation.
17   Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
18   the U.S. Government retains certain rights in this software.
19 -------------------------------------------------------------------------*/
20 
21 #include "vtkInteractorStyleRubberBand2D.h"
22 
23 #include "vtkActor.h"
24 #include "vtkCamera.h"
25 #include "vtkCommand.h"
26 #include "vtkObjectFactory.h"
27 #include "vtkRenderer.h"
28 #include "vtkRenderWindow.h"
29 #include "vtkRenderWindowInteractor.h"
30 #include "vtkUnsignedCharArray.h"
31 
32 vtkStandardNewMacro(vtkInteractorStyleRubberBand2D);
33 
34 //--------------------------------------------------------------------------
vtkInteractorStyleRubberBand2D()35 vtkInteractorStyleRubberBand2D::vtkInteractorStyleRubberBand2D()
36 {
37   this->PixelArray = vtkUnsignedCharArray::New();
38   this->Interaction = NONE;
39   this->RenderOnMouseMove = false;
40   this->StartPosition[0] = 0;
41   this->StartPosition[1] = 0;
42   this->EndPosition[0] = 0;
43   this->EndPosition[1] = 0;
44 }
45 
46 //--------------------------------------------------------------------------
~vtkInteractorStyleRubberBand2D()47 vtkInteractorStyleRubberBand2D::~vtkInteractorStyleRubberBand2D()
48 {
49   this->PixelArray->Delete();
50 }
51 
52 //--------------------------------------------------------------------------
OnLeftButtonDown()53 void vtkInteractorStyleRubberBand2D::OnLeftButtonDown()
54 {
55   if(this->Interaction == NONE)
56     {
57     if (this->Interactor->GetAltKey())
58       {
59       this->Interaction = PANNING;
60       }
61     else
62       {
63       this->Interaction = SELECTING;
64       vtkRenderWindow *renWin = this->Interactor->GetRenderWindow();
65 
66       this->StartPosition[0] = this->Interactor->GetEventPosition()[0];
67       this->StartPosition[1] = this->Interactor->GetEventPosition()[1];
68       this->EndPosition[0] = this->StartPosition[0];
69       this->EndPosition[1] = this->StartPosition[1];
70 
71       this->PixelArray->Initialize();
72       this->PixelArray->SetNumberOfComponents(4);
73       int *size = renWin->GetSize();
74       this->PixelArray->SetNumberOfTuples(size[0]*size[1]);
75 
76       renWin->GetRGBACharPixelData(0, 0, size[0]-1, size[1]-1, 1, this->PixelArray);
77       }
78     this->FindPokedRenderer(this->StartPosition[0], this->StartPosition[1]);
79     this->InvokeEvent(vtkCommand::StartInteractionEvent);
80     }
81 }
82 
83 //--------------------------------------------------------------------------
OnLeftButtonUp()84 void vtkInteractorStyleRubberBand2D::OnLeftButtonUp()
85 {
86   if(this->Interaction == SELECTING)
87     {
88     this->Interaction = NONE;
89 
90     // Clear the rubber band
91     int* size = this->Interactor->GetRenderWindow()->GetSize();
92     unsigned char* pixels = this->PixelArray->GetPointer(0);
93     this->Interactor->GetRenderWindow()->SetRGBACharPixelData(0, 0, size[0]-1, size[1]-1, pixels, 0);
94     this->Interactor->GetRenderWindow()->Frame();
95 
96     unsigned int rect[5];
97     rect[0] = this->StartPosition[0];
98     rect[1] = this->StartPosition[1];
99     rect[2] = this->EndPosition[0];
100     rect[3] = this->EndPosition[1];
101     if (this->Interactor->GetShiftKey())
102       {
103       rect[4] = SELECT_UNION;
104       }
105     else
106       {
107       rect[4] = SELECT_NORMAL;
108       }
109     this->InvokeEvent(vtkCommand::SelectionChangedEvent, reinterpret_cast<void*>(rect));
110     this->InvokeEvent(vtkCommand::EndInteractionEvent);
111     }
112   else if(this->Interaction == PANNING)
113     {
114     this->Interaction = NONE;
115     this->InvokeEvent(vtkCommand::EndInteractionEvent);
116     }
117 }
118 
119 //--------------------------------------------------------------------------
OnMiddleButtonDown()120 void vtkInteractorStyleRubberBand2D::OnMiddleButtonDown()
121 {
122   if(this->Interaction == NONE)
123     {
124     this->Interaction = PANNING;
125     this->FindPokedRenderer(
126       this->Interactor->GetEventPosition()[0],
127       this->Interactor->GetEventPosition()[1]);
128     this->InvokeEvent(vtkCommand::StartInteractionEvent);
129     }
130 }
131 
132 //--------------------------------------------------------------------------
OnMiddleButtonUp()133 void vtkInteractorStyleRubberBand2D::OnMiddleButtonUp()
134 {
135   if(this->Interaction == PANNING)
136     {
137     this->Interaction = NONE;
138     this->InvokeEvent(vtkCommand::EndInteractionEvent);
139     }
140 }
141 
142 //--------------------------------------------------------------------------
OnRightButtonDown()143 void vtkInteractorStyleRubberBand2D::OnRightButtonDown()
144 {
145   if(this->Interaction == NONE)
146     {
147     this->Interaction = ZOOMING;
148     this->FindPokedRenderer(
149       this->Interactor->GetEventPosition()[0],
150       this->Interactor->GetEventPosition()[1]);
151     this->InvokeEvent(vtkCommand::StartInteractionEvent);
152     }
153 }
154 
155 //--------------------------------------------------------------------------
OnRightButtonUp()156 void vtkInteractorStyleRubberBand2D::OnRightButtonUp()
157 {
158   if(this->Interaction == ZOOMING)
159     {
160     this->Interaction = NONE;
161     this->InvokeEvent(vtkCommand::EndInteractionEvent);
162     }
163 }
164 
165 //--------------------------------------------------------------------------
OnMouseMove()166 void vtkInteractorStyleRubberBand2D::OnMouseMove()
167 {
168   if (this->Interaction == PANNING || this->Interaction == ZOOMING)
169     {
170     vtkRenderWindowInteractor* rwi = this->GetInteractor();
171     int lastPt[] = {0, 0};
172     rwi->GetLastEventPosition(lastPt);
173     int curPt[] = {0, 0};
174     rwi->GetEventPosition(curPt);
175 
176     vtkCamera* camera = this->CurrentRenderer->GetActiveCamera();
177     double lastScale = 2.0 * camera->GetParallelScale() / this->CurrentRenderer->GetSize()[1];
178     double lastFocalPt[] = {0, 0, 0};
179     camera->GetFocalPoint(lastFocalPt);
180     double lastPos[] = {0, 0, 0};
181     camera->GetPosition(lastPos);
182 
183     if (this->Interaction == PANNING)
184       {
185       double delta[] = {0, 0, 0};
186       delta[0] = -lastScale*(curPt[0] - lastPt[0]);
187       delta[1] = -lastScale*(curPt[1] - lastPt[1]);
188       delta[2] = 0;
189       camera->SetFocalPoint(lastFocalPt[0] + delta[0], lastFocalPt[1] + delta[1], lastFocalPt[2] + delta[2]);
190       camera->SetPosition(lastPos[0] + delta[0], lastPos[1] + delta[1], lastPos[2] + delta[2]);
191       this->InvokeEvent(vtkCommand::InteractionEvent);
192       rwi->Render();
193       }
194     else if (this->Interaction == ZOOMING)
195       {
196       double motion = 10.0;
197       double dyf = motion*(curPt[1] - lastPt[1])/this->CurrentRenderer->GetCenter()[1];
198       double factor = pow(1.1, dyf);
199       camera->SetParallelScale(camera->GetParallelScale() / factor);
200       this->InvokeEvent(vtkCommand::InteractionEvent);
201       rwi->Render();
202       }
203     }
204   else if (this->Interaction == SELECTING)
205     {
206     this->EndPosition[0] = this->Interactor->GetEventPosition()[0];
207     this->EndPosition[1] = this->Interactor->GetEventPosition()[1];
208     int *size = this->Interactor->GetRenderWindow()->GetSize();
209     if (this->EndPosition[0] > (size[0]-1))
210       {
211       this->EndPosition[0] = size[0]-1;
212       }
213     if (this->EndPosition[0] < 0)
214       {
215       this->EndPosition[0] = 0;
216       }
217     if (this->EndPosition[1] > (size[1]-1))
218       {
219       this->EndPosition[1] = size[1]-1;
220       }
221     if (this->EndPosition[1] < 0)
222       {
223       this->EndPosition[1] = 0;
224       }
225     this->InvokeEvent(vtkCommand::InteractionEvent);
226     this->RedrawRubberBand();
227     }
228   else if (this->RenderOnMouseMove)
229     {
230     this->GetInteractor()->Render();
231     }
232 }
233 
234 //--------------------------------------------------------------------------
OnMouseWheelForward()235 void vtkInteractorStyleRubberBand2D::OnMouseWheelForward()
236 {
237   this->FindPokedRenderer(
238     this->Interactor->GetEventPosition()[0],
239     this->Interactor->GetEventPosition()[1]);
240   vtkCamera* camera = this->CurrentRenderer->GetActiveCamera();
241   if (!camera)
242     {
243     return;
244     }
245   this->Interaction = ZOOMING;
246   double motion = 10.0;
247   double dyf = motion * 0.2;
248   double factor = pow(1.1, dyf);
249   camera->SetParallelScale(camera->GetParallelScale() / factor);
250   this->InvokeEvent(vtkCommand::InteractionEvent);
251   this->GetInteractor()->Render();
252   this->Interaction = NONE;
253 }
254 
255 //--------------------------------------------------------------------------
OnMouseWheelBackward()256 void vtkInteractorStyleRubberBand2D::OnMouseWheelBackward()
257 {
258   this->FindPokedRenderer(
259     this->Interactor->GetEventPosition()[0],
260     this->Interactor->GetEventPosition()[1]);
261   vtkCamera* camera = this->CurrentRenderer->GetActiveCamera();
262   if (!camera)
263     {
264     return;
265     }
266   this->Interaction = ZOOMING;
267   double motion = 10.0;
268   double dyf = motion * -0.2;
269   double factor = pow(1.1, dyf);
270   camera->SetParallelScale(camera->GetParallelScale() / factor);
271   this->InvokeEvent(vtkCommand::InteractionEvent);
272   this->GetInteractor()->Render();
273   this->Interaction = NONE;
274 }
275 
276 //--------------------------------------------------------------------------
RedrawRubberBand()277 void vtkInteractorStyleRubberBand2D::RedrawRubberBand()
278 {
279   // Update the rubber band on the screen
280   int *size = this->Interactor->GetRenderWindow()->GetSize();
281 
282   vtkUnsignedCharArray *tmpPixelArray = vtkUnsignedCharArray::New();
283   tmpPixelArray->DeepCopy(this->PixelArray);
284   unsigned char *pixels = tmpPixelArray->GetPointer(0);
285 
286   int min[2], max[2];
287 
288   min[0] = this->StartPosition[0] <= this->EndPosition[0] ?
289     this->StartPosition[0] : this->EndPosition[0];
290   if (min[0] < 0) { min[0] = 0; }
291   if (min[0] >= size[0]) { min[0] = size[0] - 1; }
292 
293   min[1] = this->StartPosition[1] <= this->EndPosition[1] ?
294     this->StartPosition[1] : this->EndPosition[1];
295   if (min[1] < 0) { min[1] = 0; }
296   if (min[1] >= size[1]) { min[1] = size[1] - 1; }
297 
298   max[0] = this->EndPosition[0] > this->StartPosition[0] ?
299     this->EndPosition[0] : this->StartPosition[0];
300   if (max[0] < 0) { max[0] = 0; }
301   if (max[0] >= size[0]) { max[0] = size[0] - 1; }
302 
303   max[1] = this->EndPosition[1] > this->StartPosition[1] ?
304     this->EndPosition[1] : this->StartPosition[1];
305   if (max[1] < 0) { max[1] = 0; }
306   if (max[1] >= size[1]) { max[1] = size[1] - 1; }
307 
308   int i;
309   for (i = min[0]; i <= max[0]; i++)
310     {
311     pixels[4*(min[1]*size[0]+i)] = 255 ^ pixels[4*(min[1]*size[0]+i)];
312     pixels[4*(min[1]*size[0]+i)+1] = 255 ^ pixels[4*(min[1]*size[0]+i)+1];
313     pixels[4*(min[1]*size[0]+i)+2] = 255 ^ pixels[4*(min[1]*size[0]+i)+2];
314     pixels[4*(max[1]*size[0]+i)] = 255 ^ pixels[4*(max[1]*size[0]+i)];
315     pixels[4*(max[1]*size[0]+i)+1] = 255 ^ pixels[4*(max[1]*size[0]+i)+1];
316     pixels[4*(max[1]*size[0]+i)+2] = 255 ^ pixels[4*(max[1]*size[0]+i)+2];
317     }
318   for (i = min[1]+1; i < max[1]; i++)
319     {
320     pixels[4*(i*size[0]+min[0])] = 255 ^ pixels[4*(i*size[0]+min[0])];
321     pixels[4*(i*size[0]+min[0])+1] = 255 ^ pixels[4*(i*size[0]+min[0])+1];
322     pixels[4*(i*size[0]+min[0])+2] = 255 ^ pixels[4*(i*size[0]+min[0])+2];
323     pixels[4*(i*size[0]+max[0])] = 255 ^ pixels[4*(i*size[0]+max[0])];
324     pixels[4*(i*size[0]+max[0])+1] = 255 ^ pixels[4*(i*size[0]+max[0])+1];
325     pixels[4*(i*size[0]+max[0])+2] = 255 ^ pixels[4*(i*size[0]+max[0])+2];
326     }
327 
328   this->Interactor->GetRenderWindow()->SetRGBACharPixelData(0, 0, size[0]-1, size[1]-1, pixels, 0);
329   this->Interactor->GetRenderWindow()->Frame();
330 
331   tmpPixelArray->Delete();
332 }
333 
334 //--------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)335 void vtkInteractorStyleRubberBand2D::PrintSelf(ostream& os, vtkIndent indent)
336 {
337   this->Superclass::PrintSelf(os, indent);
338   os << indent << "Interaction: " << this->Interaction << endl;
339   os << indent << "RenderOnMouseMove: " << this->RenderOnMouseMove << endl;
340   os << indent << "StartPosition: " << this->StartPosition[0] << "," << this->StartPosition[1] << endl;
341   os << indent << "EndPosition: " << this->EndPosition[0] << "," << this->EndPosition[1] << endl;
342 }
343