AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
TwoHandRotateLogic.cs
Go to the documentation of this file.
1 // Copyright (c) Microsoft Corporation. All rights reserved.
2 // Licensed under the MIT License. See LICENSE in the project root for license information.
3 
4 using System.Collections.Generic;
5 using UnityEngine;
6 using UnityEngine.Assertions;
7 
8 namespace HoloToolkit.Unity.InputModule.Utilities.Interactions
9 {
19  public class TwoHandRotateLogic
20  {
24  private const float MinHandDistanceForPitchM = 0.1f;
25 
29  private const float RotationMultiplier = 2f;
30 
36  private AxisConstraint rotationConstraint;
37 
41  private Vector3 previousHandlebarRotation;
42 
48  private AxisConstraint currentRotationConstraint;
49 
57  private Vector3 ProjectHandlebarGivenConstraint(AxisConstraint constraint, Vector3 handlebarRotation, Transform manipulationRoot)
58  {
59  Vector3 result = handlebarRotation;
60  switch (constraint)
61  {
62  case AxisConstraint.XAxisOnly:
63  result.x = 0;
64  break;
65  case AxisConstraint.YAxisOnly:
66  result.y = 0;
67  break;
68  case AxisConstraint.ZAxisOnly:
69  result.z = 0;
70  break;
71  }
72  return CameraCache.Main.transform.TransformDirection(result);
73  }
74 
81  private Vector3 GetHandlebarDirection(Dictionary<uint, Vector3> handsPressedMap, Transform manipulationRoot)
82  {
83  var handsEnumerator = handsPressedMap.Values.GetEnumerator();
84  handsEnumerator.MoveNext();
85  var hand1 = handsEnumerator.Current;
86  handsEnumerator.MoveNext();
87  var hand2 = handsEnumerator.Current;
88 
89  // We project the handlebar direction into camera space because otherwise when we move our body the handlebard will move even
90  // though, relative to our heads, the handlebar is not moving.
91  hand1 = CameraCache.Main.transform.InverseTransformPoint(hand1);
92  hand2 = CameraCache.Main.transform.InverseTransformPoint(hand2);
93 
94  return hand2 - hand1;
95  }
96 
101  public TwoHandRotateLogic(AxisConstraint constrainRotation)
102  {
103  rotationConstraint = constrainRotation;
104  }
105 
113  public void Setup(Dictionary<uint, Vector3> handsPressedMap, Transform manipulationRoot)
114  {
115  currentRotationConstraint = rotationConstraint;
116  previousHandlebarRotation = GetHandlebarDirection(handsPressedMap, manipulationRoot);
117  }
118 
126  public Quaternion Update(Dictionary<uint, Vector3> handsPressedMap, Transform manipulationRoot, Quaternion currentRotation)
127  {
128  var handlebarDirection = GetHandlebarDirection(handsPressedMap, manipulationRoot);
129  var handlebarDirectionProjected = ProjectHandlebarGivenConstraint(currentRotationConstraint, handlebarDirection, manipulationRoot);
130  var prevHandlebarDirectionProjected = ProjectHandlebarGivenConstraint(currentRotationConstraint, previousHandlebarRotation, manipulationRoot);
131  previousHandlebarRotation = handlebarDirection;
132 
133  var rotationDelta = Quaternion.FromToRotation(prevHandlebarDirectionProjected, handlebarDirectionProjected);
134 
135  var angle = 0f;
136  var axis = Vector3.zero;
137  rotationDelta.ToAngleAxis(out angle, out axis);
138  angle *= RotationMultiplier;
139 
140  if (currentRotationConstraint == AxisConstraint.YAxisOnly)
141  {
142  // If we are rotating about Y axis, then make sure we rotate about global Y axis.
143  // Since the angle is obtained from a quaternion, we need to properly orient it (up or down) based
144  // on the original axis-angle representation.
145  axis = Vector3.up * Vector3.Dot(axis, Vector3.up);
146  }
147  return Quaternion.AngleAxis(angle, axis) * currentRotation;
148  }
149  }
150 }
TwoHandRotateLogic(AxisConstraint constrainRotation)
TwoHandRotateLogic Constructor
Quaternion Update(Dictionary< uint, Vector3 > handsPressedMap, Transform manipulationRoot, Quaternion currentRotation)
Updates internal states based on current Controller/hand states.
void Setup(Dictionary< uint, Vector3 > handsPressedMap, Transform manipulationRoot)
Initializes twohand system with controller/hand source info: the Dictionary collection already filled...
The purpose of this class is to provide a cached reference to the main camera. Calling Camera...
Definition: CameraCache.cs:12
static Camera Main
Returns a cached reference to the main camera and uses Camera.main if it hasn&#39;t been cached yet...
Definition: CameraCache.cs:20
Implements common logic for rotating holograms using a handlebar metaphor. each frame, object_rotation_delta = rotation_delta(current_hands_vector, previous_hands_vector) where hands_vector is the vector between two hand/controller positions.