1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkInteractorStyleMultiTouchCamera.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 "vtkInteractorStyleMultiTouchCamera.h"
16
17 #include "vtkCamera.h"
18 #include "vtkCallbackCommand.h"
19 #include "vtkMath.h"
20 #include "vtkObjectFactory.h"
21 #include "vtkRenderWindow.h"
22 #include "vtkRenderWindowInteractor.h"
23 #include "vtkRenderer.h"
24
25 vtkStandardNewMacro(vtkInteractorStyleMultiTouchCamera);
26
27 //----------------------------------------------------------------------------
vtkInteractorStyleMultiTouchCamera()28 vtkInteractorStyleMultiTouchCamera::vtkInteractorStyleMultiTouchCamera()
29 {
30 this->MotionFactor = 10.0;
31 this->PointersDownCount = 0;
32 for (int i = 0; i < VTKI_MAX_POINTERS; ++i)
33 {
34 this->PointersDown[i] = 0;
35 }
36 }
37
38 //----------------------------------------------------------------------------
~vtkInteractorStyleMultiTouchCamera()39 vtkInteractorStyleMultiTouchCamera::~vtkInteractorStyleMultiTouchCamera()
40 {
41 }
42
43 //----------------------------------------------------------------------------
OnMouseMove()44 void vtkInteractorStyleMultiTouchCamera::OnMouseMove()
45 {
46 int pointer = this->Interactor->GetPointerIndex();
47
48 this->FindPokedRenderer(this->Interactor->GetEventPositions(pointer)[0],
49 this->Interactor->GetEventPositions(pointer)[1]);
50 if (this->State == VTKIS_TWO_POINTER)
51 {
52 this->AdjustCamera();
53 this->InvokeEvent(vtkCommand::InteractionEvent, NULL);
54 }
55 else
56 {
57 this->Superclass::OnMouseMove();
58 }
59 }
60
61 //----------------------------------------------------------------------------
OnLeftButtonDown()62 void vtkInteractorStyleMultiTouchCamera::OnLeftButtonDown()
63 {
64 int pointer = this->Interactor->GetPointerIndex();
65
66 // if it is already down ignore this event
67 if (this->PointersDown[pointer])
68 {
69 return;
70 }
71
72 this->FindPokedRenderer(this->Interactor->GetEventPositions(pointer)[0],
73 this->Interactor->GetEventPositions(pointer)[1]);
74 if (this->CurrentRenderer == NULL)
75 {
76 return;
77 }
78
79 this->PointersDown[pointer] = 1;
80 this->PointersDownCount++;
81
82 // do the standard single pointer event handling
83 if (this->PointersDownCount == 1)
84 {
85 this->Superclass::OnLeftButtonDown();
86 return;
87 }
88
89 // if going from 1 to 2 pointers stop the one pointer action
90 if (this->PointersDownCount == 2)
91 {
92 switch (this->State)
93 {
94 case VTKIS_DOLLY:
95 this->EndDolly();
96 break;
97
98 case VTKIS_PAN:
99 this->EndPan();
100 break;
101
102 case VTKIS_SPIN:
103 this->EndSpin();
104 break;
105
106 case VTKIS_ROTATE:
107 this->EndRotate();
108 break;
109 }
110 // start the multipointer action
111 this->StartTwoPointer();
112 return;
113 }
114
115 // if going from 2 to 3 pointers stop the two pointer action
116 if (this->PointersDownCount == 3 && this->State == VTKIS_TWO_POINTER)
117 {
118 this->EndTwoPointer();
119 }
120
121 }
122
123 //----------------------------------------------------------------------------
OnLeftButtonUp()124 void vtkInteractorStyleMultiTouchCamera::OnLeftButtonUp()
125 {
126 int pointer = this->Interactor->GetPointerIndex();
127
128 // if it is already up, ignore this event
129 if (!this->PointersDown[pointer])
130 {
131 return;
132 }
133
134 this->PointersDownCount--;
135 this->PointersDown[pointer] = 0;
136
137 // if we were just one pointer then do the usual handling
138 if (this->PointersDownCount == 0)
139 {
140 this->Superclass::OnLeftButtonUp();
141 return;
142 }
143
144 switch (this->State)
145 {
146 case VTKIS_TWO_POINTER:
147 this->EndTwoPointer();
148 break;
149 }
150
151 if ( this->Interactor )
152 {
153 this->ReleaseFocus();
154 }
155 }
156
distance2D(int * a,int * b)157 double distance2D(int *a, int *b)
158 {
159 return sqrt((double)(a[0] - b[0])*(a[0] - b[0]) + (double)(a[1]-b[1])*(a[1]-b[1]));
160 }
161
162 //----------------------------------------------------------------------------
AdjustCamera()163 void vtkInteractorStyleMultiTouchCamera::AdjustCamera()
164 {
165 if ( this->CurrentRenderer == NULL )
166 {
167 return;
168 }
169
170 vtkRenderWindowInteractor *rwi = this->Interactor;
171
172 // OK we have two pointers, that means 4 constraints
173 // P1.x P1.y P2.x P2.y
174 //
175 // We use those 4 contraints to control:
176 // Zoom (variant is the distance between points - 1 DOF)
177 // Roll (variant is the angle formed by the line connecting the points - 1 DOF)
178 // Position (variant is the X,Y position of the midpoint of the line - 2 DOF)
179 //
180
181
182 // find the moving and non moving points
183 int eventPI = rwi->GetPointerIndex();
184 int otherPI = 0;
185
186 for (int i = 0; i < VTKI_MAX_POINTERS; ++i)
187 {
188 if (this->PointersDown[i] > 0 && i != eventPI)
189 {
190 otherPI = i;
191 break;
192 }
193 }
194
195 // compute roll - 1 DOF
196 double oldAngle =
197 vtkMath::DegreesFromRadians( atan2( (double)rwi->GetLastEventPositions(eventPI)[1] - rwi->GetLastEventPositions(otherPI)[1],
198 (double)rwi->GetLastEventPositions(eventPI)[0] - rwi->GetLastEventPositions(otherPI)[0] ) );
199
200 double newAngle =
201 vtkMath::DegreesFromRadians( atan2( (double)rwi->GetEventPositions(eventPI)[1] - rwi->GetEventPositions(otherPI)[1],
202 (double)rwi->GetEventPositions(eventPI)[0] - rwi->GetEventPositions(otherPI)[0] ) );
203
204
205 vtkCamera *camera = this->CurrentRenderer->GetActiveCamera();
206 camera->Roll( newAngle - oldAngle );
207
208 // compute dolly/scale - 1 DOF
209 double oldDist = distance2D(rwi->GetLastEventPositions(otherPI), rwi->GetLastEventPositions(eventPI));
210 double newDist = distance2D(rwi->GetEventPositions(otherPI), rwi->GetEventPositions(eventPI));
211
212 double dyf = newDist/oldDist;
213 if (camera->GetParallelProjection())
214 {
215 camera->SetParallelScale(camera->GetParallelScale() / dyf);
216 }
217 else
218 {
219 camera->Dolly(dyf);
220 if (this->AutoAdjustCameraClippingRange)
221 {
222 this->CurrentRenderer->ResetCameraClippingRange();
223 }
224 }
225
226 // handle panning - 2 DOF
227 double viewFocus[4], focalDepth, viewPoint[3];
228 double newPickPoint[4], oldPickPoint[4], motionVector[3];
229
230 // Calculate the focal depth since we'll be using it a lot
231 camera->GetFocalPoint(viewFocus);
232 this->ComputeWorldToDisplay(viewFocus[0], viewFocus[1], viewFocus[2],
233 viewFocus);
234 focalDepth = viewFocus[2];
235
236 this->ComputeDisplayToWorld((rwi->GetEventPositions(eventPI)[0] + rwi->GetEventPositions(otherPI)[0])/2.0,
237 (rwi->GetEventPositions(eventPI)[1] + rwi->GetEventPositions(otherPI)[1])/2.0,
238 focalDepth,
239 newPickPoint);
240
241 // Has to recalc old mouse point since the viewport has moved,
242 // so can't move it outside the loop
243 this->ComputeDisplayToWorld((rwi->GetLastEventPositions(eventPI)[0] + rwi->GetLastEventPositions(otherPI)[0])/2.0,
244 (rwi->GetLastEventPositions(eventPI)[1] + rwi->GetLastEventPositions(otherPI)[1])/2.0,
245 focalDepth,
246 oldPickPoint);
247
248 // Camera motion is reversed
249 motionVector[0] = oldPickPoint[0] - newPickPoint[0];
250 motionVector[1] = oldPickPoint[1] - newPickPoint[1];
251 motionVector[2] = oldPickPoint[2] - newPickPoint[2];
252
253 camera->GetFocalPoint(viewFocus);
254 camera->GetPosition(viewPoint);
255 camera->SetFocalPoint(motionVector[0] + viewFocus[0],
256 motionVector[1] + viewFocus[1],
257 motionVector[2] + viewFocus[2]);
258
259 camera->SetPosition(motionVector[0] + viewPoint[0],
260 motionVector[1] + viewPoint[1],
261 motionVector[2] + viewPoint[2]);
262
263 // clean up
264 if (this->Interactor->GetLightFollowCamera())
265 {
266 this->CurrentRenderer->UpdateLightsGeometryToFollowCamera();
267 }
268 camera->OrthogonalizeViewUp();
269
270 rwi->Render();
271 }
272
273 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)274 void vtkInteractorStyleMultiTouchCamera::PrintSelf(ostream& os, vtkIndent indent)
275 {
276 this->Superclass::PrintSelf(os,indent);
277 os << indent << "MotionFactor: " << this->MotionFactor << "\n";
278 }
279