1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkInteractorStyleTrackballActor.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 "vtkInteractorStyleTrackballActor.h"
16
17 #include "vtkCallbackCommand.h"
18 #include "vtkCamera.h"
19 #include "vtkCellPicker.h"
20 #include "vtkMath.h"
21 #include "vtkMatrix4x4.h"
22 #include "vtkObjectFactory.h"
23 #include "vtkProp3D.h"
24 #include "vtkRenderWindowInteractor.h"
25 #include "vtkRenderer.h"
26 #include "vtkTransform.h"
27
28 vtkStandardNewMacro(vtkInteractorStyleTrackballActor);
29
30 //------------------------------------------------------------------------------
vtkInteractorStyleTrackballActor()31 vtkInteractorStyleTrackballActor::vtkInteractorStyleTrackballActor()
32 {
33 this->MotionFactor = 10.0;
34 this->InteractionProp = nullptr;
35 this->InteractionPicker = vtkCellPicker::New();
36 this->InteractionPicker->SetTolerance(0.001);
37 }
38
39 //------------------------------------------------------------------------------
~vtkInteractorStyleTrackballActor()40 vtkInteractorStyleTrackballActor::~vtkInteractorStyleTrackballActor()
41 {
42 this->InteractionPicker->Delete();
43 }
44
45 //------------------------------------------------------------------------------
OnMouseMove()46 void vtkInteractorStyleTrackballActor::OnMouseMove()
47 {
48 int x = this->Interactor->GetEventPosition()[0];
49 int y = this->Interactor->GetEventPosition()[1];
50
51 switch (this->State)
52 {
53 case VTKIS_ROTATE:
54 this->FindPokedRenderer(x, y);
55 this->Rotate();
56 this->InvokeEvent(vtkCommand::InteractionEvent, nullptr);
57 break;
58
59 case VTKIS_PAN:
60 this->FindPokedRenderer(x, y);
61 this->Pan();
62 this->InvokeEvent(vtkCommand::InteractionEvent, nullptr);
63 break;
64
65 case VTKIS_DOLLY:
66 this->FindPokedRenderer(x, y);
67 this->Dolly();
68 this->InvokeEvent(vtkCommand::InteractionEvent, nullptr);
69 break;
70
71 case VTKIS_SPIN:
72 this->FindPokedRenderer(x, y);
73 this->Spin();
74 this->InvokeEvent(vtkCommand::InteractionEvent, nullptr);
75 break;
76
77 case VTKIS_USCALE:
78 this->FindPokedRenderer(x, y);
79 this->UniformScale();
80 this->InvokeEvent(vtkCommand::InteractionEvent, nullptr);
81 break;
82 }
83 }
84
85 //------------------------------------------------------------------------------
OnLeftButtonDown()86 void vtkInteractorStyleTrackballActor::OnLeftButtonDown()
87 {
88 int x = this->Interactor->GetEventPosition()[0];
89 int y = this->Interactor->GetEventPosition()[1];
90
91 this->FindPokedRenderer(x, y);
92 this->FindPickedActor(x, y);
93 if (this->CurrentRenderer == nullptr || this->InteractionProp == nullptr)
94 {
95 return;
96 }
97
98 this->GrabFocus(this->EventCallbackCommand);
99 if (this->Interactor->GetShiftKey())
100 {
101 this->StartPan();
102 }
103 else if (this->Interactor->GetControlKey())
104 {
105 this->StartSpin();
106 }
107 else
108 {
109 this->StartRotate();
110 }
111 }
112
113 //------------------------------------------------------------------------------
OnLeftButtonUp()114 void vtkInteractorStyleTrackballActor::OnLeftButtonUp()
115 {
116 switch (this->State)
117 {
118 case VTKIS_PAN:
119 this->EndPan();
120 break;
121
122 case VTKIS_SPIN:
123 this->EndSpin();
124 break;
125
126 case VTKIS_ROTATE:
127 this->EndRotate();
128 break;
129 }
130
131 if (this->Interactor)
132 {
133 this->ReleaseFocus();
134 }
135 }
136
137 //------------------------------------------------------------------------------
OnMiddleButtonDown()138 void vtkInteractorStyleTrackballActor::OnMiddleButtonDown()
139 {
140 int x = this->Interactor->GetEventPosition()[0];
141 int y = this->Interactor->GetEventPosition()[1];
142
143 this->FindPokedRenderer(x, y);
144 this->FindPickedActor(x, y);
145 if (this->CurrentRenderer == nullptr || this->InteractionProp == nullptr)
146 {
147 return;
148 }
149
150 this->GrabFocus(this->EventCallbackCommand);
151 if (this->Interactor->GetControlKey())
152 {
153 this->StartDolly();
154 }
155 else
156 {
157 this->StartPan();
158 }
159 }
160
161 //------------------------------------------------------------------------------
OnMiddleButtonUp()162 void vtkInteractorStyleTrackballActor::OnMiddleButtonUp()
163 {
164 switch (this->State)
165 {
166 case VTKIS_DOLLY:
167 this->EndDolly();
168 break;
169
170 case VTKIS_PAN:
171 this->EndPan();
172 break;
173 }
174
175 if (this->Interactor)
176 {
177 this->ReleaseFocus();
178 }
179 }
180
181 //------------------------------------------------------------------------------
OnRightButtonDown()182 void vtkInteractorStyleTrackballActor::OnRightButtonDown()
183 {
184 int x = this->Interactor->GetEventPosition()[0];
185 int y = this->Interactor->GetEventPosition()[1];
186
187 this->FindPokedRenderer(x, y);
188 this->FindPickedActor(x, y);
189 if (this->CurrentRenderer == nullptr || this->InteractionProp == nullptr)
190 {
191 return;
192 }
193
194 this->GrabFocus(this->EventCallbackCommand);
195 this->StartUniformScale();
196 }
197
198 //------------------------------------------------------------------------------
OnRightButtonUp()199 void vtkInteractorStyleTrackballActor::OnRightButtonUp()
200 {
201 switch (this->State)
202 {
203 case VTKIS_USCALE:
204 this->EndUniformScale();
205 break;
206 }
207
208 if (this->Interactor)
209 {
210 this->ReleaseFocus();
211 }
212 }
213
214 //------------------------------------------------------------------------------
Rotate()215 void vtkInteractorStyleTrackballActor::Rotate()
216 {
217 if (this->CurrentRenderer == nullptr || this->InteractionProp == nullptr)
218 {
219 return;
220 }
221
222 vtkRenderWindowInteractor* rwi = this->Interactor;
223 vtkCamera* cam = this->CurrentRenderer->GetActiveCamera();
224
225 // First get the origin of the assembly
226 double* obj_center = this->InteractionProp->GetCenter();
227
228 // GetLength gets the length of the diagonal of the bounding box
229 double boundRadius = this->InteractionProp->GetLength() * 0.5;
230
231 // Get the view up and view right vectors
232 double view_up[3], view_look[3], view_right[3];
233
234 cam->OrthogonalizeViewUp();
235 cam->ComputeViewPlaneNormal();
236 cam->GetViewUp(view_up);
237 vtkMath::Normalize(view_up);
238 cam->GetViewPlaneNormal(view_look);
239 vtkMath::Cross(view_up, view_look, view_right);
240 vtkMath::Normalize(view_right);
241
242 // Get the furtherest point from object position+origin
243 double outsidept[3];
244
245 outsidept[0] = obj_center[0] + view_right[0] * boundRadius;
246 outsidept[1] = obj_center[1] + view_right[1] * boundRadius;
247 outsidept[2] = obj_center[2] + view_right[2] * boundRadius;
248
249 // Convert them to display coord
250 double disp_obj_center[3];
251
252 this->ComputeWorldToDisplay(obj_center[0], obj_center[1], obj_center[2], disp_obj_center);
253
254 this->ComputeWorldToDisplay(outsidept[0], outsidept[1], outsidept[2], outsidept);
255
256 double radius = sqrt(vtkMath::Distance2BetweenPoints(disp_obj_center, outsidept));
257 double nxf = (rwi->GetEventPosition()[0] - disp_obj_center[0]) / radius;
258
259 double nyf = (rwi->GetEventPosition()[1] - disp_obj_center[1]) / radius;
260
261 double oxf = (rwi->GetLastEventPosition()[0] - disp_obj_center[0]) / radius;
262
263 double oyf = (rwi->GetLastEventPosition()[1] - disp_obj_center[1]) / radius;
264
265 if (((nxf * nxf + nyf * nyf) <= 1.0) && ((oxf * oxf + oyf * oyf) <= 1.0))
266 {
267 double newXAngle = vtkMath::DegreesFromRadians(asin(nxf));
268 double newYAngle = vtkMath::DegreesFromRadians(asin(nyf));
269 double oldXAngle = vtkMath::DegreesFromRadians(asin(oxf));
270 double oldYAngle = vtkMath::DegreesFromRadians(asin(oyf));
271
272 double scale[3];
273 scale[0] = scale[1] = scale[2] = 1.0;
274
275 double** rotate = new double*[2];
276
277 rotate[0] = new double[4];
278 rotate[1] = new double[4];
279
280 rotate[0][0] = newXAngle - oldXAngle;
281 rotate[0][1] = view_up[0];
282 rotate[0][2] = view_up[1];
283 rotate[0][3] = view_up[2];
284
285 rotate[1][0] = oldYAngle - newYAngle;
286 rotate[1][1] = view_right[0];
287 rotate[1][2] = view_right[1];
288 rotate[1][3] = view_right[2];
289
290 this->Prop3DTransform(this->InteractionProp, obj_center, 2, rotate, scale);
291
292 delete[] rotate[0];
293 delete[] rotate[1];
294 delete[] rotate;
295
296 if (this->AutoAdjustCameraClippingRange)
297 {
298 this->CurrentRenderer->ResetCameraClippingRange();
299 }
300
301 rwi->Render();
302 }
303 }
304
305 //------------------------------------------------------------------------------
Spin()306 void vtkInteractorStyleTrackballActor::Spin()
307 {
308 if (this->CurrentRenderer == nullptr || this->InteractionProp == nullptr)
309 {
310 return;
311 }
312
313 vtkRenderWindowInteractor* rwi = this->Interactor;
314 vtkCamera* cam = this->CurrentRenderer->GetActiveCamera();
315
316 // Get the axis to rotate around = vector from eye to origin
317
318 double* obj_center = this->InteractionProp->GetCenter();
319
320 double motion_vector[3];
321 double view_point[3];
322
323 if (cam->GetParallelProjection())
324 {
325 // If parallel projection, want to get the view plane normal...
326 cam->ComputeViewPlaneNormal();
327 cam->GetViewPlaneNormal(motion_vector);
328 }
329 else
330 {
331 // Perspective projection, get vector from eye to center of actor
332 cam->GetPosition(view_point);
333 motion_vector[0] = view_point[0] - obj_center[0];
334 motion_vector[1] = view_point[1] - obj_center[1];
335 motion_vector[2] = view_point[2] - obj_center[2];
336 vtkMath::Normalize(motion_vector);
337 }
338
339 double disp_obj_center[3];
340
341 this->ComputeWorldToDisplay(obj_center[0], obj_center[1], obj_center[2], disp_obj_center);
342
343 double newAngle =
344 vtkMath::DegreesFromRadians(atan2(rwi->GetEventPosition()[1] - disp_obj_center[1],
345 rwi->GetEventPosition()[0] - disp_obj_center[0]));
346
347 double oldAngle =
348 vtkMath::DegreesFromRadians(atan2(rwi->GetLastEventPosition()[1] - disp_obj_center[1],
349 rwi->GetLastEventPosition()[0] - disp_obj_center[0]));
350
351 double scale[3];
352 scale[0] = scale[1] = scale[2] = 1.0;
353
354 double** rotate = new double*[1];
355 rotate[0] = new double[4];
356
357 rotate[0][0] = newAngle - oldAngle;
358 rotate[0][1] = motion_vector[0];
359 rotate[0][2] = motion_vector[1];
360 rotate[0][3] = motion_vector[2];
361
362 this->Prop3DTransform(this->InteractionProp, obj_center, 1, rotate, scale);
363
364 delete[] rotate[0];
365 delete[] rotate;
366
367 if (this->AutoAdjustCameraClippingRange)
368 {
369 this->CurrentRenderer->ResetCameraClippingRange();
370 }
371
372 rwi->Render();
373 }
374
375 //------------------------------------------------------------------------------
Pan()376 void vtkInteractorStyleTrackballActor::Pan()
377 {
378 if (this->CurrentRenderer == nullptr || this->InteractionProp == nullptr)
379 {
380 return;
381 }
382
383 vtkRenderWindowInteractor* rwi = this->Interactor;
384
385 // Use initial center as the origin from which to pan
386
387 double* obj_center = this->InteractionProp->GetCenter();
388
389 double disp_obj_center[3], new_pick_point[4];
390 double old_pick_point[4], motion_vector[3];
391
392 this->ComputeWorldToDisplay(obj_center[0], obj_center[1], obj_center[2], disp_obj_center);
393
394 this->ComputeDisplayToWorld(
395 rwi->GetEventPosition()[0], rwi->GetEventPosition()[1], disp_obj_center[2], new_pick_point);
396
397 this->ComputeDisplayToWorld(rwi->GetLastEventPosition()[0], rwi->GetLastEventPosition()[1],
398 disp_obj_center[2], old_pick_point);
399
400 motion_vector[0] = new_pick_point[0] - old_pick_point[0];
401 motion_vector[1] = new_pick_point[1] - old_pick_point[1];
402 motion_vector[2] = new_pick_point[2] - old_pick_point[2];
403
404 if (this->InteractionProp->GetUserMatrix() != nullptr)
405 {
406 vtkTransform* t = vtkTransform::New();
407 t->PostMultiply();
408 t->SetMatrix(this->InteractionProp->GetUserMatrix());
409 t->Translate(motion_vector[0], motion_vector[1], motion_vector[2]);
410 this->InteractionProp->GetUserMatrix()->DeepCopy(t->GetMatrix());
411 t->Delete();
412 }
413 else
414 {
415 this->InteractionProp->AddPosition(motion_vector[0], motion_vector[1], motion_vector[2]);
416 }
417
418 if (this->AutoAdjustCameraClippingRange)
419 {
420 this->CurrentRenderer->ResetCameraClippingRange();
421 }
422
423 rwi->Render();
424 }
425
426 //------------------------------------------------------------------------------
Dolly()427 void vtkInteractorStyleTrackballActor::Dolly()
428 {
429 if (this->CurrentRenderer == nullptr || this->InteractionProp == nullptr)
430 {
431 return;
432 }
433
434 vtkRenderWindowInteractor* rwi = this->Interactor;
435 vtkCamera* cam = this->CurrentRenderer->GetActiveCamera();
436
437 double view_point[3], view_focus[3];
438 double motion_vector[3];
439
440 cam->GetPosition(view_point);
441 cam->GetFocalPoint(view_focus);
442
443 double* center = this->CurrentRenderer->GetCenter();
444
445 int dy = rwi->GetEventPosition()[1] - rwi->GetLastEventPosition()[1];
446 double yf = dy / center[1] * this->MotionFactor;
447 double dollyFactor = pow(1.1, yf);
448
449 dollyFactor -= 1.0;
450 motion_vector[0] = (view_point[0] - view_focus[0]) * dollyFactor;
451 motion_vector[1] = (view_point[1] - view_focus[1]) * dollyFactor;
452 motion_vector[2] = (view_point[2] - view_focus[2]) * dollyFactor;
453
454 if (this->InteractionProp->GetUserMatrix() != nullptr)
455 {
456 vtkTransform* t = vtkTransform::New();
457 t->PostMultiply();
458 t->SetMatrix(this->InteractionProp->GetUserMatrix());
459 t->Translate(motion_vector[0], motion_vector[1], motion_vector[2]);
460 this->InteractionProp->GetUserMatrix()->DeepCopy(t->GetMatrix());
461 t->Delete();
462 }
463 else
464 {
465 this->InteractionProp->AddPosition(motion_vector);
466 }
467
468 if (this->AutoAdjustCameraClippingRange)
469 {
470 this->CurrentRenderer->ResetCameraClippingRange();
471 }
472
473 rwi->Render();
474 }
475
476 //------------------------------------------------------------------------------
UniformScale()477 void vtkInteractorStyleTrackballActor::UniformScale()
478 {
479 if (this->CurrentRenderer == nullptr || this->InteractionProp == nullptr)
480 {
481 return;
482 }
483
484 vtkRenderWindowInteractor* rwi = this->Interactor;
485
486 int dy = rwi->GetEventPosition()[1] - rwi->GetLastEventPosition()[1];
487
488 double* obj_center = this->InteractionProp->GetCenter();
489 double* center = this->CurrentRenderer->GetCenter();
490
491 double yf = dy / center[1] * this->MotionFactor;
492 double scaleFactor = pow(1.1, yf);
493
494 double** rotate = nullptr;
495
496 double scale[3];
497 scale[0] = scale[1] = scale[2] = scaleFactor;
498
499 this->Prop3DTransform(this->InteractionProp, obj_center, 0, rotate, scale);
500
501 if (this->AutoAdjustCameraClippingRange)
502 {
503 this->CurrentRenderer->ResetCameraClippingRange();
504 }
505
506 rwi->Render();
507 }
508
509 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)510 void vtkInteractorStyleTrackballActor::PrintSelf(ostream& os, vtkIndent indent)
511 {
512 this->Superclass::PrintSelf(os, indent);
513 }
514
515 //------------------------------------------------------------------------------
FindPickedActor(int x,int y)516 void vtkInteractorStyleTrackballActor::FindPickedActor(int x, int y)
517 {
518 this->InteractionPicker->Pick(x, y, 0.0, this->CurrentRenderer);
519 vtkProp* prop = this->InteractionPicker->GetViewProp();
520 if (prop != nullptr)
521 {
522 this->InteractionProp = vtkProp3D::SafeDownCast(prop);
523 }
524 else
525 {
526 this->InteractionProp = nullptr;
527 }
528 }
529
530 //------------------------------------------------------------------------------
Prop3DTransform(vtkProp3D * prop3D,double * boxCenter,int numRotation,double ** rotate,double * scale)531 void vtkInteractorStyleTrackballActor::Prop3DTransform(
532 vtkProp3D* prop3D, double* boxCenter, int numRotation, double** rotate, double* scale)
533 {
534 vtkMatrix4x4* oldMatrix = vtkMatrix4x4::New();
535 prop3D->GetMatrix(oldMatrix);
536
537 double orig[3];
538 prop3D->GetOrigin(orig);
539
540 vtkTransform* newTransform = vtkTransform::New();
541 newTransform->PostMultiply();
542 if (prop3D->GetUserMatrix() != nullptr)
543 {
544 newTransform->SetMatrix(prop3D->GetUserMatrix());
545 }
546 else
547 {
548 newTransform->SetMatrix(oldMatrix);
549 }
550
551 newTransform->Translate(-(boxCenter[0]), -(boxCenter[1]), -(boxCenter[2]));
552
553 for (int i = 0; i < numRotation; i++)
554 {
555 newTransform->RotateWXYZ(rotate[i][0], rotate[i][1], rotate[i][2], rotate[i][3]);
556 }
557
558 if ((scale[0] * scale[1] * scale[2]) != 0.0)
559 {
560 newTransform->Scale(scale[0], scale[1], scale[2]);
561 }
562
563 newTransform->Translate(boxCenter[0], boxCenter[1], boxCenter[2]);
564
565 // now try to get the composite of translate, rotate, and scale
566 newTransform->Translate(-(orig[0]), -(orig[1]), -(orig[2]));
567 newTransform->PreMultiply();
568 newTransform->Translate(orig[0], orig[1], orig[2]);
569
570 if (prop3D->GetUserMatrix() != nullptr)
571 {
572 newTransform->GetMatrix(prop3D->GetUserMatrix());
573 }
574 else
575 {
576 prop3D->SetPosition(newTransform->GetPosition());
577 prop3D->SetScale(newTransform->GetScale());
578 prop3D->SetOrientation(newTransform->GetOrientation());
579 }
580 oldMatrix->Delete();
581 newTransform->Delete();
582 }
583