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 "vtkRenderWindow.h"
28 #include "vtkRenderWindowInteractor.h"
29 #include "vtkRenderer.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       const 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     const int* size = this->Interactor->GetRenderWindow()->GetSize();
92     unsigned char* pixels = this->PixelArray->GetPointer(0);
93     this->Interactor->GetRenderWindow()->SetRGBACharPixelData(
94       0, 0, size[0] - 1, size[1] - 1, pixels, 0);
95     this->Interactor->GetRenderWindow()->Frame();
96 
97     unsigned int rect[5];
98     rect[0] = this->StartPosition[0];
99     rect[1] = this->StartPosition[1];
100     rect[2] = this->EndPosition[0];
101     rect[3] = this->EndPosition[1];
102     if (this->Interactor->GetShiftKey())
103     {
104       rect[4] = SELECT_UNION;
105     }
106     else
107     {
108       rect[4] = SELECT_NORMAL;
109     }
110     this->InvokeEvent(vtkCommand::SelectionChangedEvent, reinterpret_cast<void*>(rect));
111     this->InvokeEvent(vtkCommand::EndInteractionEvent);
112   }
113   else if (this->Interaction == PANNING)
114   {
115     this->Interaction = NONE;
116     this->InvokeEvent(vtkCommand::EndInteractionEvent);
117   }
118 }
119 
120 //------------------------------------------------------------------------------
OnMiddleButtonDown()121 void vtkInteractorStyleRubberBand2D::OnMiddleButtonDown()
122 {
123   if (this->Interaction == NONE)
124   {
125     this->Interaction = PANNING;
126     this->FindPokedRenderer(
127       this->Interactor->GetEventPosition()[0], 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], this->Interactor->GetEventPosition()[1]);
150     this->InvokeEvent(vtkCommand::StartInteractionEvent);
151   }
152 }
153 
154 //------------------------------------------------------------------------------
OnRightButtonUp()155 void vtkInteractorStyleRubberBand2D::OnRightButtonUp()
156 {
157   if (this->Interaction == ZOOMING)
158   {
159     this->Interaction = NONE;
160     this->InvokeEvent(vtkCommand::EndInteractionEvent);
161   }
162 }
163 
164 //------------------------------------------------------------------------------
OnMouseMove()165 void vtkInteractorStyleRubberBand2D::OnMouseMove()
166 {
167   if (this->Interaction == PANNING || this->Interaction == ZOOMING)
168   {
169     vtkRenderWindowInteractor* rwi = this->GetInteractor();
170     int lastPt[] = { 0, 0 };
171     rwi->GetLastEventPosition(lastPt);
172     int curPt[] = { 0, 0 };
173     rwi->GetEventPosition(curPt);
174 
175     vtkCamera* camera = this->CurrentRenderer->GetActiveCamera();
176     double lastScale = 2.0 * camera->GetParallelScale() / this->CurrentRenderer->GetSize()[1];
177     double lastFocalPt[] = { 0, 0, 0 };
178     camera->GetFocalPoint(lastFocalPt);
179     double lastPos[] = { 0, 0, 0 };
180     camera->GetPosition(lastPos);
181 
182     if (this->Interaction == PANNING)
183     {
184       double delta[] = { 0, 0, 0 };
185       delta[0] = -lastScale * (curPt[0] - lastPt[0]);
186       delta[1] = -lastScale * (curPt[1] - lastPt[1]);
187       delta[2] = 0;
188       camera->SetFocalPoint(
189         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     const 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], this->Interactor->GetEventPosition()[1]);
239   vtkCamera* camera = this->CurrentRenderer->GetActiveCamera();
240   if (!camera)
241   {
242     return;
243   }
244   this->Interaction = ZOOMING;
245   double motion = 10.0;
246   double dyf = motion * 0.2;
247   double factor = pow(1.1, dyf);
248   camera->SetParallelScale(camera->GetParallelScale() / factor);
249   this->InvokeEvent(vtkCommand::InteractionEvent);
250   this->GetInteractor()->Render();
251   this->Interaction = NONE;
252 }
253 
254 //------------------------------------------------------------------------------
OnMouseWheelBackward()255 void vtkInteractorStyleRubberBand2D::OnMouseWheelBackward()
256 {
257   this->FindPokedRenderer(
258     this->Interactor->GetEventPosition()[0], this->Interactor->GetEventPosition()[1]);
259   vtkCamera* camera = this->CurrentRenderer->GetActiveCamera();
260   if (!camera)
261   {
262     return;
263   }
264   this->Interaction = ZOOMING;
265   double motion = 10.0;
266   double dyf = motion * -0.2;
267   double factor = pow(1.1, dyf);
268   camera->SetParallelScale(camera->GetParallelScale() / factor);
269   this->InvokeEvent(vtkCommand::InteractionEvent);
270   this->GetInteractor()->Render();
271   this->Interaction = NONE;
272 }
273 
274 //------------------------------------------------------------------------------
RedrawRubberBand()275 void vtkInteractorStyleRubberBand2D::RedrawRubberBand()
276 {
277   // Update the rubber band on the screen
278   const int* size = this->Interactor->GetRenderWindow()->GetSize();
279 
280   vtkUnsignedCharArray* tmpPixelArray = vtkUnsignedCharArray::New();
281   tmpPixelArray->DeepCopy(this->PixelArray);
282   unsigned char* pixels = tmpPixelArray->GetPointer(0);
283 
284   int min[2], max[2];
285 
286   min[0] =
287     this->StartPosition[0] <= this->EndPosition[0] ? this->StartPosition[0] : this->EndPosition[0];
288   if (min[0] < 0)
289   {
290     min[0] = 0;
291   }
292   if (min[0] >= size[0])
293   {
294     min[0] = size[0] - 1;
295   }
296 
297   min[1] =
298     this->StartPosition[1] <= this->EndPosition[1] ? this->StartPosition[1] : this->EndPosition[1];
299   if (min[1] < 0)
300   {
301     min[1] = 0;
302   }
303   if (min[1] >= size[1])
304   {
305     min[1] = size[1] - 1;
306   }
307 
308   max[0] =
309     this->EndPosition[0] > this->StartPosition[0] ? this->EndPosition[0] : this->StartPosition[0];
310   if (max[0] < 0)
311   {
312     max[0] = 0;
313   }
314   if (max[0] >= size[0])
315   {
316     max[0] = size[0] - 1;
317   }
318 
319   max[1] =
320     this->EndPosition[1] > this->StartPosition[1] ? this->EndPosition[1] : this->StartPosition[1];
321   if (max[1] < 0)
322   {
323     max[1] = 0;
324   }
325   if (max[1] >= size[1])
326   {
327     max[1] = size[1] - 1;
328   }
329 
330   int i;
331   for (i = min[0]; i <= max[0]; i++)
332   {
333     pixels[4 * (min[1] * size[0] + i)] = 255 ^ pixels[4 * (min[1] * size[0] + i)];
334     pixels[4 * (min[1] * size[0] + i) + 1] = 255 ^ pixels[4 * (min[1] * size[0] + i) + 1];
335     pixels[4 * (min[1] * size[0] + i) + 2] = 255 ^ pixels[4 * (min[1] * size[0] + i) + 2];
336     pixels[4 * (max[1] * size[0] + i)] = 255 ^ pixels[4 * (max[1] * size[0] + i)];
337     pixels[4 * (max[1] * size[0] + i) + 1] = 255 ^ pixels[4 * (max[1] * size[0] + i) + 1];
338     pixels[4 * (max[1] * size[0] + i) + 2] = 255 ^ pixels[4 * (max[1] * size[0] + i) + 2];
339   }
340   for (i = min[1] + 1; i < max[1]; i++)
341   {
342     pixels[4 * (i * size[0] + min[0])] = 255 ^ pixels[4 * (i * size[0] + min[0])];
343     pixels[4 * (i * size[0] + min[0]) + 1] = 255 ^ pixels[4 * (i * size[0] + min[0]) + 1];
344     pixels[4 * (i * size[0] + min[0]) + 2] = 255 ^ pixels[4 * (i * size[0] + min[0]) + 2];
345     pixels[4 * (i * size[0] + max[0])] = 255 ^ pixels[4 * (i * size[0] + max[0])];
346     pixels[4 * (i * size[0] + max[0]) + 1] = 255 ^ pixels[4 * (i * size[0] + max[0]) + 1];
347     pixels[4 * (i * size[0] + max[0]) + 2] = 255 ^ pixels[4 * (i * size[0] + max[0]) + 2];
348   }
349 
350   this->Interactor->GetRenderWindow()->SetRGBACharPixelData(
351     0, 0, size[0] - 1, size[1] - 1, pixels, 0);
352   this->Interactor->GetRenderWindow()->Frame();
353 
354   tmpPixelArray->Delete();
355 }
356 
357 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)358 void vtkInteractorStyleRubberBand2D::PrintSelf(ostream& os, vtkIndent indent)
359 {
360   this->Superclass::PrintSelf(os, indent);
361   os << indent << "Interaction: " << this->Interaction << endl;
362   os << indent << "RenderOnMouseMove: " << this->RenderOnMouseMove << endl;
363   os << indent << "StartPosition: " << this->StartPosition[0] << "," << this->StartPosition[1]
364      << endl;
365   os << indent << "EndPosition: " << this->EndPosition[0] << "," << this->EndPosition[1] << endl;
366 }
367