|
a |
|
b/app/RotationUtil.py |
|
|
1 |
import numpy as np |
|
|
2 |
import math |
|
|
3 |
|
|
|
4 |
from resources.LeapSDK.v53_python39 import Leap |
|
|
5 |
|
|
|
6 |
|
|
|
7 |
def get_order(): |
|
|
8 |
############## |
|
|
9 |
# i, j, k, n |
|
|
10 |
# n = parity of axis permutation (even=False, odd=True) |
|
|
11 |
# from https://github.com/dfelinto/blender/blob/master/source/blender/blenlib/intern/math_rotation.c |
|
|
12 |
############## |
|
|
13 |
|
|
|
14 |
return [0, 1, 2, False] # XYZ |
|
|
15 |
# return [0, 2, 1, True] # XZY |
|
|
16 |
# return [1, 0, 2, True] # YXZ |
|
|
17 |
# return [1, 2, 0, False] # YZX |
|
|
18 |
# return [2, 0, 1, False] # ZXY |
|
|
19 |
# return [2, 1, 0, True] # ZYX |
|
|
20 |
|
|
|
21 |
|
|
|
22 |
def _rot2eulsimple(rotmat): |
|
|
23 |
eul = np.zeros(3) |
|
|
24 |
if -1 < rotmat[1, 1] < 1: |
|
|
25 |
eul[1] = math.acos(rotmat[1, 1]) |
|
|
26 |
if rotmat[1, 1] >= 1.0: |
|
|
27 |
eul[1] = 0 |
|
|
28 |
if rotmat[1, 1] <= -1.0: |
|
|
29 |
eul[1] = np.pi |
|
|
30 |
|
|
|
31 |
if rotmat[0, 0] < 1 and rotmat[1, 1] > -1: |
|
|
32 |
eul[0] = math.acos(rotmat[0, 0]) |
|
|
33 |
if rotmat[1, 1] >= 1.0: |
|
|
34 |
eul[0] = 0 |
|
|
35 |
if rotmat[1, 1] <= -1.0: |
|
|
36 |
eul[0] = np.pi |
|
|
37 |
|
|
|
38 |
eul[2] = 0 |
|
|
39 |
return eul |
|
|
40 |
|
|
|
41 |
|
|
|
42 |
def _rot2eul(rotmat): |
|
|
43 |
############## |
|
|
44 |
# i, j, k, n |
|
|
45 |
# n = parity of axis permutation (even=False, odd=True) |
|
|
46 |
# from https://github.com/dfelinto/blender/blob/master/source/blender/blenlib/intern/math_rotation.c |
|
|
47 |
############## |
|
|
48 |
|
|
|
49 |
# order = [0, 1, 2, False] # XYZ |
|
|
50 |
# order = [0, 2, 1, True] # XZY |
|
|
51 |
# order = [1, 0, 2, True] # YXZ |
|
|
52 |
# order = [1, 2, 0, False] # YZX |
|
|
53 |
# order = [2, 0, 1, False] # ZXY |
|
|
54 |
# order = [2, 1, 0, True] # ZYX |
|
|
55 |
|
|
|
56 |
order = get_order() |
|
|
57 |
|
|
|
58 |
i = int(order[2]) |
|
|
59 |
j = int(order[1]) |
|
|
60 |
k = int(order[0]) |
|
|
61 |
parity = order[3] |
|
|
62 |
|
|
|
63 |
eul1 = np.zeros(3) |
|
|
64 |
eul2 = np.zeros(3) |
|
|
65 |
|
|
|
66 |
cy = np.hypot(rotmat[i, i], rotmat[i, j]) |
|
|
67 |
|
|
|
68 |
if cy > Leap.EPSILON: |
|
|
69 |
eul1[i] = math.atan2(rotmat[j, k], rotmat[k, k]) |
|
|
70 |
eul1[j] = math.atan2(-rotmat[i, k], cy) |
|
|
71 |
eul1[k] = math.atan2(rotmat[i, j], rotmat[i, i]) |
|
|
72 |
|
|
|
73 |
eul2[i] = math.atan2(-rotmat[j, k], -rotmat[k, k]) |
|
|
74 |
eul2[j] = math.atan2(-rotmat[i, k], -cy) |
|
|
75 |
eul2[k] = math.atan2(-rotmat[i, j], -rotmat[i, i]) |
|
|
76 |
|
|
|
77 |
else: |
|
|
78 |
eul1[i] = math.atan2(-rotmat[k, j], rotmat[j, j]) |
|
|
79 |
eul1[j] = math.atan2(-rotmat[i, k], cy) |
|
|
80 |
eul1[k] = 0.0 |
|
|
81 |
|
|
|
82 |
eul2 = eul1 |
|
|
83 |
|
|
|
84 |
# parity of axis permutation (even=False, odd=True) |
|
|
85 |
if not parity: |
|
|
86 |
eul1 = np.negative(eul1) |
|
|
87 |
eul2 = np.negative(eul2) |
|
|
88 |
|
|
|
89 |
# return best, which is just the one with lowest values in it |
|
|
90 |
if np.sum(np.absolute(eul1)) > np.sum(np.absolute(eul2)): |
|
|
91 |
return eul2 |
|
|
92 |
return eul1 |
|
|
93 |
|
|
|
94 |
|
|
|
95 |
def quat2mat(quat): |
|
|
96 |
q0 = math.sqrt(2) * quat[0] |
|
|
97 |
q1 = math.sqrt(2) * quat[1] |
|
|
98 |
q2 = math.sqrt(2) * quat[2] |
|
|
99 |
q3 = math.sqrt(2) * quat[3] |
|
|
100 |
|
|
|
101 |
qda = q0 * q1 |
|
|
102 |
qdb = q0 * q2 |
|
|
103 |
qdc = q0 * q3 |
|
|
104 |
qaa = q1 * q1 |
|
|
105 |
qab = q1 * q2 |
|
|
106 |
qac = q1 * q3 |
|
|
107 |
qbb = q2 * q2 |
|
|
108 |
qbc = q2 * q3 |
|
|
109 |
qcc = q3 * q3 |
|
|
110 |
|
|
|
111 |
mat = np.zeros((3, 3)) |
|
|
112 |
mat[0, 0] = 1.0 - qbb - qcc |
|
|
113 |
mat[1, 0] = qdc + qab |
|
|
114 |
mat[2, 0] = -qdb + qac |
|
|
115 |
|
|
|
116 |
mat[0, 1] = -qdc + qab |
|
|
117 |
mat[1, 1] = 1.0 - qaa - qcc |
|
|
118 |
mat[2, 1] = qda + qbc |
|
|
119 |
|
|
|
120 |
mat[0, 2] = qdb + qac |
|
|
121 |
mat[1, 2] = -qda + qbc |
|
|
122 |
mat[2, 2] = 1.0 - qaa - qbb |
|
|
123 |
|
|
|
124 |
return mat |
|
|
125 |
|
|
|
126 |
|
|
|
127 |
def vec2quat(v1, v2): |
|
|
128 |
a = np.divide(v1, np.linalg.norm(v1)) |
|
|
129 |
b = np.divide(v2, np.linalg.norm(v2)) |
|
|
130 |
|
|
|
131 |
xUnitVec = np.array([1, 0, 0]) |
|
|
132 |
yUnitVec = np.array([0, 1, 0]) |
|
|
133 |
|
|
|
134 |
dot_p = np.dot(a, b) |
|
|
135 |
|
|
|
136 |
if dot_p < -1 + Leap.EPSILON: |
|
|
137 |
tmpvec3 = np.cross(xUnitVec, a) |
|
|
138 |
if np.linalg.norm(tmpvec3) < Leap.EPSILON: |
|
|
139 |
tmpvec3 = np.cross(yUnitVec, a) |
|
|
140 |
tmpvec3 = np.divide(tmpvec3, np.linalg.norm(tmpvec3)) |
|
|
141 |
|
|
|
142 |
t = np.pi * 0.5 |
|
|
143 |
s = np.sin(t) |
|
|
144 |
q = np.zeros(4) |
|
|
145 |
q[0] = np.cos(t) |
|
|
146 |
q[1] = tmpvec3[0]*s |
|
|
147 |
q[2] = tmpvec3[1]*s |
|
|
148 |
q[3] = tmpvec3[2]*s |
|
|
149 |
return q |
|
|
150 |
|
|
|
151 |
if dot_p > 1 - Leap.EPSILON: |
|
|
152 |
return np.array([0, 0, 0, 1]) |
|
|
153 |
|
|
|
154 |
tmpvec3 = np.cross(a, b) |
|
|
155 |
q = np.append(1 + dot_p, tmpvec3) |
|
|
156 |
return np.divide(q, np.linalg.norm(q)) |
|
|
157 |
|
|
|
158 |
|
|
|
159 |
def rot2quat(rotmat): |
|
|
160 |
q = np.zeros(4) |
|
|
161 |
|
|
|
162 |
tr = 0.25 * (1 + np.trace(rotmat)) |
|
|
163 |
if tr > Leap.EPSILON: |
|
|
164 |
s = np.sqrt(tr) |
|
|
165 |
q[0] = s |
|
|
166 |
s = 1.0 / (4.0 * s) |
|
|
167 |
q[1] = (rotmat[1, 2] - rotmat[2, 1]) * s |
|
|
168 |
q[2] = (rotmat[2, 0] - rotmat[0, 2]) * s |
|
|
169 |
q[3] = (rotmat[0, 1] - rotmat[1, 0]) * s |
|
|
170 |
return normalize_quat(q) |
|
|
171 |
|
|
|
172 |
if rotmat[0, 0] > rotmat[1, 1] and rotmat[0, 0] > rotmat[2, 2]: |
|
|
173 |
s = 2.0 * np.sqrt(1.0 + rotmat[0, 0] - rotmat[1, 1] - rotmat[2, 2]) |
|
|
174 |
q[1] = 0.25 * s |
|
|
175 |
s = 1.0 / s |
|
|
176 |
q[0] = (rotmat[1, 2] - rotmat[2, 1]) * s |
|
|
177 |
q[2] = (rotmat[1, 0] - rotmat[0, 1]) * s |
|
|
178 |
q[3] = (rotmat[2, 0] - rotmat[0, 2]) * s |
|
|
179 |
return normalize_quat(q) |
|
|
180 |
|
|
|
181 |
if rotmat[1, 1] > rotmat[2, 2]: |
|
|
182 |
s = 2.0 * np.sqrt(1.0 + rotmat[1, 1] - rotmat[0, 0] - rotmat[2, 2]) |
|
|
183 |
q[2] = 0.25 * s |
|
|
184 |
s = 1.0 / s |
|
|
185 |
q[0] = (rotmat[2, 0] - rotmat[0, 2]) * s |
|
|
186 |
q[1] = (rotmat[1, 0] - rotmat[0, 1]) * s |
|
|
187 |
q[3] = (rotmat[2, 1] - rotmat[1, 2]) * s |
|
|
188 |
return normalize_quat(q) |
|
|
189 |
|
|
|
190 |
s = 2.0 * np.sqrt(1.0 + rotmat[2, 2] - rotmat[0, 0] - rotmat[1, 1]) |
|
|
191 |
q[3] = 0.25 * s |
|
|
192 |
s = 1.0 / s |
|
|
193 |
q[0] = (rotmat[0, 1] - rotmat[1, 0]) * s |
|
|
194 |
q[1] = (rotmat[2, 0] - rotmat[0, 2]) * s |
|
|
195 |
q[2] = (rotmat[2, 1] - rotmat[1, 2]) * s |
|
|
196 |
return normalize_quat(q) |
|
|
197 |
|
|
|
198 |
|
|
|
199 |
def normalize_quat(q): |
|
|
200 |
scal = np.sqrt(np.dot(q, q)) |
|
|
201 |
if scal != 0.0: |
|
|
202 |
return np.kron(q, 1.0 / scal) |
|
|
203 |
|
|
|
204 |
q[1] = 1.0 |
|
|
205 |
q[0] = q[2] = q[3] = 0.0 |
|
|
206 |
return q |
|
|
207 |
|
|
|
208 |
|
|
|
209 |
def conjugate_quat(q): |
|
|
210 |
q[1] = -q[1] |
|
|
211 |
q[2] = -q[2] |
|
|
212 |
q[3] = -q[4] |
|
|
213 |
return q |
|
|
214 |
|
|
|
215 |
|
|
|
216 |
def multiply_quat(q1, q2): |
|
|
217 |
q = np.zeros(4) |
|
|
218 |
t0 = q1[0] * q2[0] - q1[1] * q2[1] - q1[2] * q2[2] - q1[3] * q2[3] |
|
|
219 |
t1 = q1[0] * q2[1] + q1[1] * q2[0] + q1[2] * q2[3] - q1[3] * q2[2] |
|
|
220 |
t2 = q1[0] * q2[2] + q1[2] * q2[0] + q1[3] * q2[1] - q1[1] * q2[3] |
|
|
221 |
q[3] = q1[0] * q2[3] + q1[3] * q2[0] + q1[1] * q2[2] - q1[2] * q2[1] |
|
|
222 |
q[0] = t0 |
|
|
223 |
q[1] = t1 |
|
|
224 |
q[2] = t2 |
|
|
225 |
return q |
|
|
226 |
|
|
|
227 |
|
|
|
228 |
def vec2eul(v1, v2): |
|
|
229 |
quaternions = vec2quat(v1, v2) |
|
|
230 |
rotmat = quat2mat(quaternions) |
|
|
231 |
euler = _rot2eul(rotmat) |
|
|
232 |
return euler[0], euler[1], euler[2] |
|
|
233 |
|
|
|
234 |
|
|
|
235 |
def rot2eul(rotmat): |
|
|
236 |
euler = _rot2eul(rotmat) |
|
|
237 |
return euler[0], euler[1], euler[2] |
|
|
238 |
|
|
|
239 |
|
|
|
240 |
def quat_diff(q_prev, q_next): |
|
|
241 |
q_prev = conjugate_quat(q_prev) |
|
|
242 |
q_prev = np.kron(q_prev, 1.0 / np.dot(q_prev, q_prev)) |
|
|
243 |
return multiply_quat(q_prev, q_next) |
|
|
244 |
|
|
|
245 |
|
|
|
246 |
def quat_between_rot(rotmat_prev, rotmat_next): |
|
|
247 |
# TODO: normalize rotation matrix |
|
|
248 |
return quat_diff(rot2quat(rotmat_prev), rot2quat(rotmat_next)) |