Tanoda
TransformTool.cs
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (C) Ultraleap, Inc. 2011-2020. *
3 * *
4 * Use subject to the terms of the Apache License 2.0 available at *
5 * http://www.apache.org/licenses/LICENSE-2.0, or another agreement *
6 * between Ultraleap and you, your company or other organization. *
7 ******************************************************************************/
8
10using Leap.Unity.Query;
11using System;
12using System.Collections;
13using System.Collections.Generic;
14using UnityEngine;
15
16namespace Leap.Unity.Examples {
17
18 [AddComponentMenu("")]
19 public class TransformTool : MonoBehaviour {
20
21 [Tooltip("The scene's InteractionManager, used to get InteractionControllers and "
22 + "manage handle state.")]
23 public InteractionManager interactionManager;
24
25 [Tooltip("The target object to be moved by this tool.")]
26 public Transform target;
27
28 private Vector3 _moveBuffer = Vector3.zero;
29 private Quaternion _rotateBuffer = Quaternion.identity;
30
31 private HashSet<TransformHandle> _transformHandles = new HashSet<TransformHandle>();
32
33 private enum ToolState { Idle, Translating, Rotating }
34 private ToolState _toolState = ToolState.Idle;
35 private HashSet<TransformHandle> _activeHandles = new HashSet<TransformHandle>();
36
37 private HashSet<TranslationAxis> _activeTranslationAxes = new HashSet<TranslationAxis>();
38
39 void Start() {
40 if (interactionManager == null) {
41 interactionManager = InteractionManager.instance;
42 }
43
44 foreach (var handle in GetComponentsInChildren<TransformHandle>()) {
45 _transformHandles.Add(handle);
46 }
47
48 // PhysicsCallbacks is useful for creating explicit pre-physics and post-physics
49 // behaviour.
50 PhysicsCallbacks.OnPostPhysics += onPostPhysics;
51 }
52
53 void Update() {
54 // Enable or disable handles based on hand proximity and tool state.
55 updateHandles();
56 }
57
58 #region Handle Movement / Rotation
59
64 public void NotifyHandleMovement(Vector3 deltaPosition) {
65 _moveBuffer += deltaPosition;
66 }
67
72 public void NotifyHandleRotation(Quaternion deltaRotation) {
73 _rotateBuffer = deltaRotation * _rotateBuffer;
74 }
75
76 private void onPostPhysics() {
77 // Hooked up via PhysicsCallbacks in Start(), this method will run after
78 // FixedUpdate and after PhysX has run. We take the opportunity to immediately
79 // manipulate the target object's and this object's transforms using the
80 // accumulated information about movement and rotation from the Transform Handles.
81
82 // Apply accumulated movement and rotation to target object.
83 target.transform.rotation = _rotateBuffer * target.transform.rotation;
84 this.transform.rotation = target.transform.rotation;
85
86 // Match this transform with the target object's (this will move child
87 // TransformHandles' transforms).
88 target.transform.position += _moveBuffer;
89 this.transform.position = target.transform.position;
90
91 // Explicitly sync TransformHandles' rigidbodies with their transforms,
92 // which moved along with this object's transform because they are children of it.
93 foreach (var handle in _transformHandles) {
94 handle.syncRigidbodyWithTransform();
95 }
96
97 // Reset movement and rotation buffers.
98 _moveBuffer = Vector3.zero;
99 _rotateBuffer = Quaternion.identity;
100 }
101
102 #endregion
103
104 #region Handle Visibility
105
106 private void updateHandles() {
107 switch (_toolState) {
108 case ToolState.Idle:
109 // Find the closest handle to any InteractionHand.
110 TransformHandle closestHandleToAnyHand = null;
111 float closestHandleDist = float.PositiveInfinity;
112 foreach (var intController in interactionManager.interactionControllers
113 .Query()
114 .Where(controller => controller.isTracked)) {
115 if (!intController.isPrimaryHovering) continue;
116 TransformHandle testHandle = intController.primaryHoveredObject
117 .gameObject
118 .GetComponent<TransformHandle>();
119
120 if (testHandle == null || !_transformHandles.Contains(testHandle)) continue;
121
122 float testDist = intController.primaryHoverDistance;
123 if (testDist < closestHandleDist) {
124 closestHandleToAnyHand = testHandle;
125 closestHandleDist = testDist;
126 }
127 }
128
129 // While idle, only show the closest handle to any hand, hide other handles.
130 foreach (var handle in _transformHandles) {
131 if (closestHandleToAnyHand != null && handle == closestHandleToAnyHand) {
132 handle.EnsureVisible();
133 }
134 else {
135 handle.EnsureHidden();
136 }
137 }
138 break;
139
140 case ToolState.Translating:
141 // While translating, show all translation handles except the other handle
142 // on the same axis, and hide rotation handles.
143 foreach (var handle in _transformHandles) {
144 if (handle is TransformTranslationHandle) {
145 var translateHandle = handle as TransformTranslationHandle;
146
147 if (!_activeHandles.Contains(translateHandle)
148 && _activeTranslationAxes.Contains(translateHandle.axis)) {
149 handle.EnsureHidden();
150 }
151 else {
152 handle.EnsureVisible();
153 }
154 }
155 else {
156 handle.EnsureHidden();
157 }
158 }
159 break;
160
161 case ToolState.Rotating:
162 // While rotating, only show the active rotating handle.
163 foreach (var handle in _transformHandles) {
164 if (_activeHandles.Contains(handle)) {
165 handle.EnsureVisible();
166 }
167 else {
168 handle.EnsureHidden();
169 }
170 }
171 break;
172 }
173 }
174
180 switch (_toolState) {
181 case ToolState.Idle:
182 _activeHandles.Add(handle);
183
184 if (handle is TransformTranslationHandle) {
185 _toolState = ToolState.Translating;
186 _activeTranslationAxes.Add(((TransformTranslationHandle)handle).axis);
187 }
188 else {
189 _toolState = ToolState.Rotating;
190 }
191 break;
192
193 case ToolState.Translating:
194 if (handle is TransformRotationHandle) {
195 Debug.LogError("Error: Can't rotate a transform while it is already being "
196 + "translated.");
197 }
198 else {
199 _activeHandles.Add(handle);
200 _activeTranslationAxes.Add(((TransformTranslationHandle)handle).axis);
201 }
202 break;
203
204 case ToolState.Rotating:
205 Debug.LogError("Error: Only one handle can be active while a transform is being "
206 + "rotated.");
207 break;
208 }
209 }
210
215 if (handle is TransformTranslationHandle) {
216 _activeTranslationAxes.Remove(((TransformTranslationHandle)handle).axis);
217 }
218
219 _activeHandles.Remove(handle);
220
221 switch (_toolState) {
222 case ToolState.Idle:
223 Debug.LogWarning("Warning: Handle was deactived while Tool was already idle.");
224 break;
225
226 default:
227 if (_activeHandles.Count == 0) {
228 _toolState = ToolState.Idle;
229 }
230 break;
231 }
232 }
233
234 #endregion
235
236 }
237
238}
UnityEngine.Debug Debug
Definition: TanodaServer.cs:19
InteractionManager interactionManager
void NotifyHandleRotation(Quaternion deltaRotation)
Transform handles call this method to notify the tool that they were used to rotate the target object...
void NotifyHandleDeactivated(TransformHandle handle)
Called by Handles when they are released.
void NotifyHandleMovement(Vector3 deltaPosition)
Transform handles call this method to notify the tool that they were used to move the target object.
void NotifyHandleActivated(TransformHandle handle)
Called by handles when they are grasped.