Tanoda
TestHandFactory.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
9namespace Leap {
10
11 using System;
12 using System.Collections.Generic;
13 using Leap.Unity;
14 using UnityEngine;
15
16 public static class TestHandFactory {
17
18 #region Test Frame / Hand API
19
20 public enum UnitType {
21 LeapUnits,
22 UnityUnits
23 }
24
29 public static Frame MakeTestFrame(int frameId,
30 bool includeLeftHand = true,
31 bool includeRightHand = true,
32 TestHandPose handPose = TestHandPose.HeadMountedA,
33 UnitType unitType = UnitType.LeapUnits) {
34
35 var testFrame = new Frame(frameId, 0, 120.0f,
36 new List<Hand>());
37
38 if (includeLeftHand)
39 testFrame.Hands.Add(MakeTestHand(true, handPose, frameId, 10, unitType));
40 if (includeRightHand)
41 testFrame.Hands.Add(MakeTestHand(false, handPose, frameId, 20, unitType));
42
43 return testFrame;
44 }
45
52 public static Hand MakeTestHand(bool isLeft, LeapTransform leftHandTransform,
53 int frameId = 0, int handId = 0,
54 UnitType unitType = UnitType.LeapUnits) {
55
56 // Apply the appropriate mirroring if this is a right hand.
57 if (!isLeft) {
58 leftHandTransform.translation = new Vector(-leftHandTransform.translation.x,
59 leftHandTransform.translation.y, leftHandTransform.translation.z);
60
61 leftHandTransform.rotation = new LeapQuaternion(-leftHandTransform.rotation.x,
62 leftHandTransform.rotation.y,
63 leftHandTransform.rotation.z,
64 -leftHandTransform.rotation.w);
65
66 leftHandTransform.MirrorX();
67 }
68
69 // Leap space is oriented differently than Unity space, so correct for this here.
70 var hand = makeLeapSpaceTestHand(frameId, handId, isLeft)
71 .Transform(leftHandTransform);
72 var correctingQuaternion = Quaternion.Euler(90f, 0f, 180f);
73 var correctingLeapQuaternion = new LeapQuaternion(correctingQuaternion.x,
74 correctingQuaternion.y,
75 correctingQuaternion.z,
76 correctingQuaternion.w);
77
78 var transformedHand = hand.Transform(new LeapTransform(Vector.Zero,
79 correctingLeapQuaternion));
80
81 if (unitType == UnitType.UnityUnits) {
82 transformedHand.TransformToUnityUnits();
83 }
84
85 return transformedHand;
86 }
87
91 public static Hand MakeTestHand(bool isLeft,
92 int frameId = 0, int handId = 0,
93 UnitType unitType = UnitType.LeapUnits) {
94 return MakeTestHand(isLeft, LeapTransform.Identity, frameId, handId, unitType);
95 }
96
100 public static Hand MakeTestHand(bool isLeft, TestHandPose pose,
101 int frameId = 0, int handId = 0,
102 UnitType unitType = UnitType.LeapUnits) {
103 return MakeTestHand(isLeft, GetTestPoseLeftHandTransform(pose),
104 frameId, handId,
105 unitType);
106 }
107
108 #endregion
109
110 #region Test Hand Poses
111
112 public enum TestHandPose {
113 HeadMountedA,
114 HeadMountedB,
115 DesktopModeA,
116 ScreenTop
117 }
118
119 public static LeapTransform GetTestPoseLeftHandTransform(TestHandPose pose) {
120 LeapTransform transform = LeapTransform.Identity;
121 switch (pose) {
122 case TestHandPose.HeadMountedA:
123 transform.rotation = angleAxis(180 * Constants.DEG_TO_RAD, Vector.Forward);
124 transform.translation = new Vector(80f, 120f, 0f);
125 break;
126 case TestHandPose.HeadMountedB:
127 transform.rotation = Quaternion.Euler(30F, -10F, -20F).ToLeapQuaternion();
128 transform.translation = new Vector(220f, 270f, 130f);
129 break;
130 case TestHandPose.DesktopModeA:
131 transform.rotation = angleAxis(0f * Constants.DEG_TO_RAD, Vector.Forward)
132 .Multiply(angleAxis(-90f * Constants.DEG_TO_RAD, Vector.Right))
133 .Multiply(angleAxis(180f * Constants.DEG_TO_RAD, Vector.Up));
134 transform.translation = new Vector(120f, 0f, -170f);
135 break;
136 case TestHandPose.ScreenTop:
137 transform.rotation = angleAxis(0 * Constants.DEG_TO_RAD, Vector.Forward)
138 .Multiply(angleAxis(140 * Constants.DEG_TO_RAD, Vector.Right))
139 .Multiply(angleAxis(0 * Constants.DEG_TO_RAD, Vector.Up));
140 transform.translation = new Vector(-120f, 20f, -380f);
141 transform.scale = new Vector(1, 1, 1);
142 break;
143
144 }
145 return transform;
146 }
147
148 #endregion
149
150 #region Leap Space Hand Generation
151
152 public static Vector PepperWristOffset = new Vector(-8.87f, -0.5f, 85.12f);
153
154 private static Hand makeLeapSpaceTestHand(int frameId, int handId, bool isLeft) {
155 List<Finger> fingers = new List<Finger>(5);
156 fingers.Add(makeThumb(frameId, handId, isLeft));
157 fingers.Add(makeIndexFinger(frameId, handId, isLeft));
158 fingers.Add(makeMiddleFinger(frameId, handId, isLeft));
159 fingers.Add(makeRingFinger(frameId, handId, isLeft));
160 fingers.Add(makePinky(frameId, handId, isLeft));
161
162 Vector armWrist = new Vector(-7.05809944059f, 4.0f, 50.0f);
163 Vector elbow = armWrist + 250f * Vector.Backward;
164
165 // Adrian: The previous "armBasis" used "elbow" as a translation component.
166 Arm arm = new Arm(elbow, armWrist,(elbow + armWrist)/2, Vector.Forward,
167 250f, 41f, LeapQuaternion.Identity);
168 Hand testHand = new Hand(frameId,
169 handId,
170 1.0f,
171 0.0f,
172 0.0f,
173 0.0f,
174 0.0f,
175 85f,
176 isLeft,
177 0.0f,
178 arm,
179 fingers,
180 new Vector (0,0,0),
181 new Vector(0,0,0),
182 new Vector(0,0,0),
183 Vector.Down,
184 LeapQuaternion.Identity,
185 Vector.Forward,
186 PepperWristOffset);
187 // new Vector(-12.36385750984f, -6.5f, 81.0111342526f));
188
189 return testHand;
190 }
191
192 private static LeapQuaternion angleAxis(float angle, Vector axis) {
193 if (!axis.MagnitudeSquared.NearlyEquals(1.0f)) {
194 throw new ArgumentException("Axis must be a unit vector.");
195 }
196 float sineHalfAngle = Mathf.Sin(angle/2.0f);
197 LeapQuaternion q = new LeapQuaternion(sineHalfAngle * axis.x,
198 sineHalfAngle * axis.y,
199 sineHalfAngle * axis.z,
200 Mathf.Cos(angle/2.0f));
201 return q.Normalized;
202 }
203
204 private static LeapQuaternion rotationBetween(Vector fromDirection, Vector toDirection) {
205 float m = Mathf.Sqrt(2.0f + 2.0f * fromDirection.Dot(toDirection));
206 Vector w = (1.0f / m) * fromDirection.Cross(toDirection);
207 return new LeapQuaternion(w.x, w.y, w.z, 0.5f * m);
208 }
209
210 private static Finger makeThumb(int frameId, int handId, bool isLeft) {
211 Vector position = new Vector(19.3382610281f, -6.0f, 53.168484654f);
212 Vector forward = new Vector(0.636329113772f, -0.5f, -0.899787143982f);
213 Vector up = new Vector(0.804793943718f, 0.447213915513f, 0.390264553767f);
214 float[] jointLengths = {0.0f, 46.22f, 31.57f, 21.67f};
215 return makeFinger(Finger.FingerType.TYPE_THUMB, position, forward, up, jointLengths, frameId, handId, handId + 0, isLeft);
216 }
217
218 private static Finger makeIndexFinger(int frameId, int handId, bool isLeft) {
219 Vector position = new Vector(23.1812851873f, 2.0f, -23.1493459317f);
220 Vector forward = new Vector(0.166044313785f, -0.14834045293f, -0.974897120667f);
221 Vector up = new Vector(0.0249066470677f, 0.988936352868f, -0.1462345681f);
222 float[] jointLengths = {68.12f, 39.78f, 22.38f, 15.82f};
223 return makeFinger(Finger.FingerType.TYPE_INDEX, position, forward, up, jointLengths, frameId, handId, handId + 1, isLeft);
224 }
225
226 private static Finger makeMiddleFinger(int frameId, int handId, bool isLeft) {
227 Vector position = new Vector(2.78877821918f, 4.0f, -23.252105626f);
228 Vector forward = new Vector(0.0295207858556f, -0.148340452932f, -0.988495641481f);
229 Vector up = new Vector(-0.145765270107f, 0.977715980076f, -0.151075968756f);
230 float[] jointLengths = {64.60f, 44.63f, 26.33f, 17.40f};
231 return makeFinger(Finger.FingerType.TYPE_MIDDLE, position, forward, up, jointLengths, frameId, handId, handId + 2, isLeft);
232 }
233
234 private static Finger makeRingFinger(int frameId, int handId, bool isLeft) {
235 Vector position = new Vector(-17.447168266f, 4.0f, -17.2791440615f);
236 Vector forward = new Vector(-0.121317937368f, -0.148340347175f, -0.981466810174f);
237 Vector up = new Vector(-0.216910468316f, 0.968834928679f, -0.119619102602f);
238 float[] jointLengths = {58.00f, 41.37f, 25.65f, 17.30f};
239 return makeFinger(Finger.FingerType.TYPE_RING, position, forward, up, jointLengths, frameId, handId, handId + 3, isLeft);
240 }
241
242 private static Finger makePinky(int frameId, int handId, bool isLeft) {
243 Vector position = new Vector(-35.3374394559f, 0.0f, -9.72871382551f);
244 Vector forward = new Vector(-0.259328923438f, -0.105851224797f, -0.959970847306f);
245 Vector up = new Vector(-0.353350220937f, 0.935459475557f, -0.00769356576168f);
246 float[] jointLengths = {53.69f, 32.74f, 18.11f, 15.96f};
247 return makeFinger(Finger.FingerType.TYPE_PINKY, position, forward, up, jointLengths, frameId, handId, handId + 4, isLeft);
248 }
249
250
251 private static Finger makeFinger(Finger.FingerType name, Vector position, Vector forward, Vector up, float[] jointLengths,
252 int frameId, int handId, int fingerId, bool isLeft) {
253
254 forward = forward.Normalized;
255 up = up.Normalized;
256
257 Bone[] bones = new Bone[5];
258 float proximalDistance = -jointLengths[0];
259 Bone metacarpal = makeBone (Bone.BoneType.TYPE_METACARPAL, position + forward * proximalDistance, jointLengths[0], 8f, forward, up, isLeft);
260 proximalDistance += jointLengths[0];
261 bones[0] = metacarpal;
262
263 Bone proximal = makeBone (Bone.BoneType.TYPE_PROXIMAL, position + forward * proximalDistance, jointLengths[1], 8f, forward, up, isLeft);
264 proximalDistance += jointLengths[1];
265 bones[1] = proximal;
266
267 Bone intermediate = makeBone (Bone.BoneType.TYPE_INTERMEDIATE, position + forward * proximalDistance, jointLengths[2], 8f, forward, up, isLeft);
268 proximalDistance += jointLengths[2];
269 bones[2] = intermediate;
270
271 Bone distal = makeBone (Bone.BoneType.TYPE_DISTAL, position + forward * proximalDistance, jointLengths[3], 8f, forward, up, isLeft);
272 bones[3] = distal;
273
274 return new Finger(frameId,
275 handId,
276 fingerId,
277 0.0f,
278 distal.NextJoint,
279 forward,
280 8f,
281 jointLengths[1] + jointLengths[2] + jointLengths[3],
282 true,
283 name,
284 bones[0],
285 bones[1],
286 bones[2],
287 bones[3]);
288 }
289
290 private static Bone makeBone(Bone.BoneType name, Vector proximalPosition, float length, float width, Vector direction, Vector up, bool isLeft) {
291
292 LeapQuaternion rotation = UnityEngine.Quaternion.LookRotation(-direction.ToVector3(), up.ToVector3()).ToLeapQuaternion();
293
294 return new Bone(
295 proximalPosition,
296 proximalPosition + direction * length,
297 Vector.Lerp(proximalPosition, proximalPosition + direction * length, .5f),
298 direction,
299 length,
300 width,
301 name,
302 rotation);
303 }
304
305 #endregion
306
307 }
308
309 // Note: The fact that this class needs to exist is ridiculous
310 // TODO: Look into automatically returning things in Unity units? Would require changes
311 // for everything that uses the TestHandFactory.
312 public static class LeapTestProviderExtensions {
313
314 public static readonly float MM_TO_M = 1e-3f;
315
316 public static LeapTransform GetLeapTransform(Vector3 position, Quaternion rotation) {
317 Vector scale = new Vector(MM_TO_M, MM_TO_M, MM_TO_M); // Leap units -> Unity units.
318 LeapTransform transform = new LeapTransform(position.ToVector(), rotation.ToLeapQuaternion(), scale);
319 transform.MirrorZ(); // Unity is left handed.
320 return transform;
321 }
322
323 public static void TransformToUnityUnits(this Hand hand) {
324 hand.Transform(GetLeapTransform(Vector3.zero, Quaternion.identity));
325 }
326
327 }
328
329}
TestHandFactory.TestHandPose TestHandPose
Definition: LeapProvider.cs:14