Pose.cs
6.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/******************************************************************************
* Copyright (C) Leap Motion, Inc. 2011-2017. *
* Leap Motion proprietary and confidential. *
* *
* Use subject to the terms of the Leap Motion SDK Agreement available at *
* https://developer.leapmotion.com/sdk_agreement, or another agreement *
* between Leap Motion and you, your company or other organization. *
******************************************************************************/
using System;
using UnityEngine;
namespace Leap.Unity {
/// <summary>
/// A position and rotation. You can multiply two poses; this acts like Matrix4x4
/// multiplication, but Poses always have unit scale.
/// </summary>
[System.Serializable]
public struct Pose : IEquatable<Pose> {
public Vector3 position;
public Quaternion rotation;
public Pose(Vector3 position, Quaternion rotation) {
this.position = position;
this.rotation = rotation;
}
public static readonly Pose identity = new Pose(Vector3.zero, Quaternion.identity);
public Pose inverse {
get {
var invQ = Quaternion.Inverse(this.rotation);
return new Pose(-(invQ * this.position), invQ);
}
}
/// <summary>
/// Returns Pose B transformed by Pose A, like a transform hierarchy with A as the
/// parent of B.
/// </summary>
public static Pose operator *(Pose A, Pose B) {
return new Pose(A.position + (A.rotation * B.position),
A.rotation * B.rotation);
}
public bool ApproxEquals(Pose other) {
return position.ApproxEquals(other.position) && rotation.ApproxEquals(other.rotation);
}
/// <summary>
/// Returns a pose interpolated (Lerp for position, Slerp, NOT Lerp for rotation)
/// between a and b by t from 0 to 1. This method clamps t between 0 and 1; if
/// extrapolation is desired, see Extrapolate.
/// </summary>
public static Pose Lerp(Pose a, Pose b, float t) {
if (t >= 1f) return b;
if (t <= 0f) return a;
return new Pose(Vector3.Lerp(a.position, b.position, t),
Quaternion.Slerp(a.rotation, b.rotation, t));
}
/// <summary>
/// As Lerp, but doesn't clamp t between 0 and 1. Values above one extrapolate
/// forwards beyond b, while values less than zero extrapolate backwards past a.
/// </summary>
public static Pose LerpUnclamped(Pose a, Pose b, float t) {
return new Pose(Vector3.LerpUnclamped(a.position, b.position, t),
Quaternion.SlerpUnclamped(a.rotation, b.rotation, t));
}
/// <summary>
/// As LerpUnclamped, but extrapolates using time values for a and b, and a target
/// time at which to determine the extrapolated pose.
/// </summary>
public static Pose LerpUnclampedTimed(Pose a, float aTime,
Pose b, float bTime,
float extrapolateTime) {
return LerpUnclamped(a, b, extrapolateTime.MapUnclamped(aTime, bTime, 0f, 1f));
}
public override string ToString() {
return "[Pose | Position: " + this.position.ToString()
+ ", Rotation: " + this.rotation.ToString() + "]";
}
public string ToString(string format) {
return "[Pose | Position: " + this.position.ToString(format)
+ ", Rotation: " + this.rotation.ToString(format) + "]";
}
public override bool Equals(object obj) {
if (!(obj is Pose)) return false;
else return this.Equals((Pose)obj);
}
public bool Equals(Pose other) {
return other.position == this.position && other.rotation == this.rotation;
}
public override int GetHashCode() {
return new Hash() {
position,
rotation
};
}
public static bool operator ==(Pose a, Pose b) {
return a.Equals(b);
}
public static bool operator !=(Pose a, Pose b) {
return !(a.Equals(b));
}
}
public static class PoseExtensions {
/// <summary>
/// Creates a Pose using the transform's localPosition and localRotation.
/// </summary>
public static Pose ToLocalPose(this Transform t) {
return new Pose(t.localPosition, t.localRotation);
}
/// <summary>
/// Creates a Pose using the transform's position and rotation.
/// </summary>
public static Pose ToWorldPose(this Transform t) {
return new Pose(t.position, t.rotation);
}
/// <summary>
/// Sets the localPosition and localRotation of this transform to the argument pose's
/// position and rotation.
/// </summary>
public static void SetLocalPose(this Transform t, Pose localPose) {
t.localPosition = localPose.position;
t.localRotation = localPose.rotation;
}
/// <summary>
/// Sets the position and rotation of this transform to the argument pose's
/// position and rotation.
/// </summary>
public static void SetWorldPose(this Transform t, Pose worldPose) {
t.position = worldPose.position;
t.rotation = worldPose.rotation;
}
/// <summary>
/// Returns the pose (position and rotation) described by a Matrix4x4.
/// </summary>
public static Pose GetPose(this Matrix4x4 m) {
return new Pose(m.GetColumn(3),
m.GetColumn(2) == m.GetColumn(1) ? Quaternion.identity
: Quaternion.LookRotation(
m.GetColumn(2),
m.GetColumn(1)));
}
public static Vector3 GetVector3(this Matrix4x4 m) { return m.GetColumn(3); }
public static Quaternion GetQuaternion(this Matrix4x4 m) {
if (m.GetColumn(2) == m.GetColumn(1)) { return Quaternion.identity; }
return Quaternion.LookRotation(m.GetColumn(2), m.GetColumn(1));
}
public const float EPSILON = 0.0001f;
public static bool ApproxEquals(this Vector3 v0, Vector3 v1) {
return (v0 - v1).magnitude < EPSILON;
}
public static bool ApproxEquals(this Quaternion q0, Quaternion q1) {
return (q0.ToAngleAxisVector() - q1.ToAngleAxisVector()).magnitude < EPSILON;
}
}
}