quat.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. import numpy as np
  2. def _fast_cross(a, b):
  3. return np.concatenate([
  4. a[...,1:2]*b[...,2:3] - a[...,2:3]*b[...,1:2],
  5. a[...,2:3]*b[...,0:1] - a[...,0:1]*b[...,2:3],
  6. a[...,0:1]*b[...,1:2] - a[...,1:2]*b[...,0:1]], axis=-1)
  7. def eye(shape, dtype=np.float32):
  8. return np.ones(list(shape) + [4], dtype=dtype) * np.asarray([1, 0, 0, 0], dtype=dtype)
  9. def length(x):
  10. return np.sqrt(np.sum(x * x, axis=-1))
  11. def normalize(x, eps=1e-8):
  12. return x / (length(x)[...,np.newaxis] + eps)
  13. def abs(x):
  14. return np.where(x[...,0:1] > 0.0, x, -x)
  15. def from_angle_axis(angle, axis):
  16. c = np.cos(angle / 2.0)[..., np.newaxis]
  17. s = np.sin(angle / 2.0)[..., np.newaxis]
  18. q = np.concatenate([c, s * axis], axis=-1)
  19. return q
  20. def to_xform(x):
  21. qw, qx, qy, qz = x[...,0:1], x[...,1:2], x[...,2:3], x[...,3:4]
  22. x2, y2, z2 = qx + qx, qy + qy, qz + qz
  23. xx, yy, wx = qx * x2, qy * y2, qw * x2
  24. xy, yz, wy = qx * y2, qy * z2, qw * y2
  25. xz, zz, wz = qx * z2, qz * z2, qw * z2
  26. return np.concatenate([
  27. np.concatenate([1.0 - (yy + zz), xy - wz, xz + wy], axis=-1)[...,np.newaxis,:],
  28. np.concatenate([xy + wz, 1.0 - (xx + zz), yz - wx], axis=-1)[...,np.newaxis,:],
  29. np.concatenate([xz - wy, yz + wx, 1.0 - (xx + yy)], axis=-1)[...,np.newaxis,:],
  30. ], axis=-2)
  31. def to_xform_xy(x):
  32. qw, qx, qy, qz = x[...,0:1], x[...,1:2], x[...,2:3], x[...,3:4]
  33. x2, y2, z2 = qx + qx, qy + qy, qz + qz
  34. xx, yy, wx = qx * x2, qy * y2, qw * x2
  35. xy, yz, wy = qx * y2, qy * z2, qw * y2
  36. xz, zz, wz = qx * z2, qz * z2, qw * z2
  37. return np.concatenate([
  38. np.concatenate([1.0 - (yy + zz), xy - wz], axis=-1)[...,np.newaxis,:],
  39. np.concatenate([xy + wz, 1.0 - (xx + zz)], axis=-1)[...,np.newaxis,:],
  40. np.concatenate([xz - wy, yz + wx], axis=-1)[...,np.newaxis,:],
  41. ], axis=-2)
  42. def from_euler(e, order='zyx'):
  43. axis = {
  44. 'x': np.asarray([1, 0, 0], dtype=np.float32),
  45. 'y': np.asarray([0, 1, 0], dtype=np.float32),
  46. 'z': np.asarray([0, 0, 1], dtype=np.float32)}
  47. q0 = from_angle_axis(e[..., 0], axis[order[0]])
  48. q1 = from_angle_axis(e[..., 1], axis[order[1]])
  49. q2 = from_angle_axis(e[..., 2], axis[order[2]])
  50. return mul(q0, mul(q1, q2))
  51. def from_xform(ts):
  52. return normalize(
  53. np.where((ts[...,2,2] < 0.0)[...,np.newaxis],
  54. np.where((ts[...,0,0] > ts[...,1,1])[...,np.newaxis],
  55. np.concatenate([
  56. (ts[...,2,1]-ts[...,1,2])[...,np.newaxis],
  57. (1.0 + ts[...,0,0] - ts[...,1,1] - ts[...,2,2])[...,np.newaxis],
  58. (ts[...,1,0]+ts[...,0,1])[...,np.newaxis],
  59. (ts[...,0,2]+ts[...,2,0])[...,np.newaxis]], axis=-1),
  60. np.concatenate([
  61. (ts[...,0,2]-ts[...,2,0])[...,np.newaxis],
  62. (ts[...,1,0]+ts[...,0,1])[...,np.newaxis],
  63. (1.0 - ts[...,0,0] + ts[...,1,1] - ts[...,2,2])[...,np.newaxis],
  64. (ts[...,2,1]+ts[...,1,2])[...,np.newaxis]], axis=-1)),
  65. np.where((ts[...,0,0] < -ts[...,1,1])[...,np.newaxis],
  66. np.concatenate([
  67. (ts[...,1,0]-ts[...,0,1])[...,np.newaxis],
  68. (ts[...,0,2]+ts[...,2,0])[...,np.newaxis],
  69. (ts[...,2,1]+ts[...,1,2])[...,np.newaxis],
  70. (1.0 - ts[...,0,0] - ts[...,1,1] + ts[...,2,2])[...,np.newaxis]], axis=-1),
  71. np.concatenate([
  72. (1.0 + ts[...,0,0] + ts[...,1,1] + ts[...,2,2])[...,np.newaxis],
  73. (ts[...,2,1]-ts[...,1,2])[...,np.newaxis],
  74. (ts[...,0,2]-ts[...,2,0])[...,np.newaxis],
  75. (ts[...,1,0]-ts[...,0,1])[...,np.newaxis]], axis=-1))))
  76. def from_xform_xy(x):
  77. c2 = _fast_cross(x[...,0], x[...,1])
  78. c2 = c2 / np.sqrt(np.sum(np.square(c2), axis=-1))[...,np.newaxis]
  79. c1 = _fast_cross(c2, x[...,0])
  80. c1 = c1 / np.sqrt(np.sum(np.square(c1), axis=-1))[...,np.newaxis]
  81. c0 = x[...,0]
  82. return from_xform(np.concatenate([
  83. c0[...,np.newaxis],
  84. c1[...,np.newaxis],
  85. c2[...,np.newaxis]], axis=-1))
  86. def inv(q):
  87. return np.asarray([1, -1, -1, -1], dtype=np.float32) * q
  88. def mul(x, y):
  89. x0, x1, x2, x3 = x[..., 0:1], x[..., 1:2], x[..., 2:3], x[..., 3:4]
  90. y0, y1, y2, y3 = y[..., 0:1], y[..., 1:2], y[..., 2:3], y[..., 3:4]
  91. return np.concatenate([
  92. y0 * x0 - y1 * x1 - y2 * x2 - y3 * x3,
  93. y0 * x1 + y1 * x0 - y2 * x3 + y3 * x2,
  94. y0 * x2 + y1 * x3 + y2 * x0 - y3 * x1,
  95. y0 * x3 - y1 * x2 + y2 * x1 + y3 * x0], axis=-1)
  96. def inv_mul(x, y):
  97. return mul(inv(x), y)
  98. def mul_inv(x, y):
  99. return mul(x, inv(y))
  100. def mul_vec(q, x):
  101. t = 2.0 * _fast_cross(q[..., 1:], x)
  102. return x + q[..., 0][..., np.newaxis] * t + _fast_cross(q[..., 1:], t)
  103. def inv_mul_vec(q, x):
  104. return mul_vec(inv(q), x)
  105. def unroll(x):
  106. y = x.copy()
  107. for i in range(1, len(x)):
  108. d0 = np.sum( y[i] * y[i-1], axis=-1)
  109. d1 = np.sum(-y[i] * y[i-1], axis=-1)
  110. y[i][d0 < d1] = -y[i][d0 < d1]
  111. return y
  112. def between(x, y):
  113. return np.concatenate([
  114. np.sqrt(np.sum(x*x, axis=-1) * np.sum(y*y, axis=-1))[...,np.newaxis] +
  115. np.sum(x * y, axis=-1)[...,np.newaxis],
  116. _fast_cross(x, y)], axis=-1)
  117. def log(x, eps=1e-5):
  118. length = np.sqrt(np.sum(np.square(x[...,1:]), axis=-1))[...,np.newaxis]
  119. halfangle = np.where(length < eps, np.ones_like(length), np.arctan2(length, x[...,0:1]) / length)
  120. return halfangle * x[...,1:]
  121. def exp(x, eps=1e-5):
  122. halfangle = np.sqrt(np.sum(np.square(x), axis=-1))[...,np.newaxis]
  123. c = np.where(halfangle < eps, np.ones_like(halfangle), np.cos(halfangle))
  124. s = np.where(halfangle < eps, np.ones_like(halfangle), np.sinc(halfangle / np.pi))
  125. return np.concatenate([c, s * x], axis=-1)
  126. def to_scaled_angle_axis(x, eps=1e-5):
  127. return 2.0 * log(x, eps)
  128. def from_scaled_angle_axis(x, eps=1e-5):
  129. return exp(x / 2.0, eps)
  130. def fk(lrot, lpos, parents):
  131. gp, gr = [lpos[...,:1,:]], [lrot[...,:1,:]]
  132. for i in range(1, len(parents)):
  133. gp.append(mul_vec(gr[parents[i]], lpos[...,i:i+1,:]) + gp[parents[i]])
  134. gr.append(mul (gr[parents[i]], lrot[...,i:i+1,:]))
  135. return np.concatenate(gr, axis=-2), np.concatenate(gp, axis=-2)
  136. def ik(grot, gpos, parents):
  137. return (
  138. np.concatenate([
  139. grot[...,:1,:],
  140. mul(inv(grot[...,parents[1:],:]), grot[...,1:,:]),
  141. ], axis=-2),
  142. np.concatenate([
  143. gpos[...,:1,:],
  144. mul_vec(
  145. inv(grot[...,parents[1:],:]),
  146. gpos[...,1:,:] - gpos[...,parents[1:],:]),
  147. ], axis=-2))
  148. def fk_vel(lrot, lpos, lvel, lang, parents):
  149. gp, gr, gv, ga = [lpos[...,:1,:]], [lrot[...,:1,:]], [lvel[...,:1,:]], [lang[...,:1,:]]
  150. for i in range(1, len(parents)):
  151. gp.append(mul_vec(gr[parents[i]], lpos[...,i:i+1,:]) + gp[parents[i]])
  152. gr.append(mul (gr[parents[i]], lrot[...,i:i+1,:]))
  153. gv.append(mul_vec(gr[parents[i]], lvel[...,i:i+1,:]) +
  154. _fast_cross(ga[parents[i]], mul_vec(gr[parents[i]], lpos[...,i:i+1,:])) +
  155. gv[parents[i]])
  156. ga.append(mul_vec(gr[parents[i]], lang[...,i:i+1,:]) + ga[parents[i]])
  157. return (
  158. np.concatenate(gr, axis=-2),
  159. np.concatenate(gp, axis=-2),
  160. np.concatenate(gv, axis=-2),
  161. np.concatenate(ga, axis=-2))
  162. def to_euler(x, order='xyz'):
  163. q0 = x[...,0:1]
  164. q1 = x[...,1:2]
  165. q2 = x[...,2:3]
  166. q3 = x[...,3:4]
  167. if order == 'xyz':
  168. return np.concatenate([
  169. np.arctan2(2 * (q0 * q1 + q2 * q3), 1 - 2 * (q1 * q1 + q2 * q2)),
  170. np.arcsin((2 * (q0 * q2 - q3 * q1)).clip(-1,1)),
  171. np.arctan2(2 * (q0 * q3 + q1 * q2), 1 - 2 * (q2 * q2 + q3 * q3))], axis=-1)
  172. elif order == 'yzx':
  173. return np.concatenate([
  174. np.arctan2(2 * (q1 * q0 - q2 * q3), -q1 * q1 + q2 * q2 - q3 * q3 + q0 * q0),
  175. np.arctan2(2 * (q2 * q0 - q1 * q3), q1 * q1 - q2 * q2 - q3 * q3 + q0 * q0),
  176. np.arcsin((2 * (q1 * q2 + q3 * q0)).clip(-1,1))], axis=-1)
  177. else:
  178. raise NotImplementedError('Cannot convert from ordering %s' % order)