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