dual_quaternion.py 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import sympy
  2. import sys
  3. import unittest
  4. import sophus
  5. class DualQuaternion:
  6. """ Dual quaternion class """
  7. def __init__(self, real_q, inf_q):
  8. """ Dual quaternion consists of a real quaternion, and an infinitesimal
  9. quaternion """
  10. self.real_q = real_q
  11. self.inf_q = inf_q
  12. def __mul__(self, right):
  13. """ dual quaternion multiplication """
  14. return DualQuaternion(self.real_q * right.real_q,
  15. self.real_q * right.inf_q +
  16. self.inf_q * right.real_q)
  17. def __truediv__(self, scalar):
  18. """ scalar division """
  19. return DualQuaternion(self.real_q / scalar, self.inf_q / scalar)
  20. def __repr__(self):
  21. return "( " + repr(self.real_q) + \
  22. " + " + repr(self.inf_q) + ")"
  23. def __getitem__(self, key):
  24. assert (key >= 0 and key < 8)
  25. if key < 4:
  26. return self.real_q[i]
  27. else:
  28. return self.inf_q[i - 4]
  29. def squared_norm(self):
  30. """ squared norm when considering the dual quaternion as 8-tuple """
  31. return self.real_q.squared_norm() + self.inf_q.squared_norm()
  32. def conj(self):
  33. """ dual quaternion conjugate """
  34. return DualQuaternion(self.real_q.conj(), self.inf_q.conj())
  35. def inv(self):
  36. """ dual quaternion inverse """
  37. return DualQuaternion(self.real_q.inv(),
  38. -self.real_q.inv() * self.inf_q *
  39. self.real_q.inv())
  40. def simplify(self):
  41. return DualQuaternion(self.real_q.simplify(),
  42. self.inf_q.simplify())
  43. @staticmethod
  44. def identity():
  45. return DualQuaternion(sophus.Quaternion.identity(),
  46. sophus.Quaternion.zero())
  47. def __eq__(self, other):
  48. if isinstance(self, other.__class__):
  49. return self.real_q == other.real_q and self.inf_q == other.inf_q
  50. return False
  51. class TestDualQuaternion(unittest.TestCase):
  52. def setUp(self):
  53. w, s0, s1, s2 = sympy.symbols('w s0 s1 s2', real=True)
  54. x, t0, t1, t2 = sympy.symbols('x t0 t1 t2', real=True)
  55. y, u0, u1, u2 = sympy.symbols('y u0 u1 u2', real=True)
  56. z, v0, v1, v2 = sympy.symbols('z v0 v1 v2', real=True)
  57. s = sophus.Vector3(s0, s1, s2)
  58. t = sophus.Vector3(t0, t1, t2)
  59. u = sophus.Vector3(u0, u1, u2)
  60. v = sophus.Vector3(v0, v1, v2)
  61. self.a = DualQuaternion(sophus.Quaternion(w, s),
  62. sophus.Quaternion(x, t))
  63. self.b = DualQuaternion(sophus.Quaternion(y, u),
  64. sophus.Quaternion(z, v))
  65. def test_muliplications(self):
  66. product = self.a * self.a.inv()
  67. self.assertEqual(product.simplify(),
  68. DualQuaternion.identity())
  69. product = self.a.inv() * self.a
  70. self.assertEqual(product.simplify(),
  71. DualQuaternion.identity())
  72. if __name__ == '__main__':
  73. unittest.main()