def from_screw(cls, l, m, theta, d): """Returns the unit dual quaternion corresponding to a screw. Parameters ========== l : tuple unit vector parallel to the screw axis m : tuple moment of l theta : number d : number Returns ======= DualQuaternion """ (x, y, z) = l (a, b, c) = m if trigsimp(x**2 + y**2 + z**2) != 1 or trigsimp(x * a + y * b + z * c) != 0: raise ValueError( "Expected l to be a unit vector and m perpendicular to l!") q_r = Quaternion(cos(theta * S.Half), *(sin(theta * S.Half) * i for i in l)) q_d = Quaternion( -d * S.Half * sin(theta * S.Half), *(d * S.Half * cos(theta * S.Half) * i + sin(theta * S.Half) * j for i, j in zip(l, m))) return DualQuaternion(q_r, q_d)
def test_quaternion_functions(): q = Quaternion(x, y, z, w) q1 = Quaternion(1, 2, 3, 4) assert conjugate(q) == Quaternion(x, -y, -z, -w) assert q.norm() == sqrt(w**2 + x**2 + y**2 + z**2) assert q.normalize() == Quaternion(x, y, z, w) / sqrt(w**2 + x**2 + y**2 + z**2) assert q.inverse() == Quaternion(x, -y, -z, -w) / (w**2 + x**2 + y**2 + z**2) assert q.pow(2) == Quaternion(-w**2 + x**2 - y**2 - z**2, 2*x*y, 2*x*z, 2*w*x) assert q1.exp() == \ Quaternion(E * cos(sqrt(29)), 2 * sqrt(29) * E * sin(sqrt(29)) / 29, 3 * sqrt(29) * E * sin(sqrt(29)) / 29, 4 * sqrt(29) * E * sin(sqrt(29)) / 29) assert q1._ln() == \ Quaternion(log(sqrt(30)), 2 * sqrt(29) * acos(sqrt(30)/30) / 29, 3 * sqrt(29) * acos(sqrt(30)/30) / 29, 4 * sqrt(29) * acos(sqrt(30)/30) / 29) assert q1.pow_cos_sin(2) == \ Quaternion(30 * cos(2 * acos(sqrt(30)/30)), 60 * sqrt(29) * sin(2 * acos(sqrt(30)/30)) / 29, 90 * sqrt(29) * sin(2 * acos(sqrt(30)/30)) / 29, 120 * sqrt(29) * sin(2 * acos(sqrt(30)/30)) / 29) assert diff(Quaternion(x, x, x, x), x) == Quaternion(1, 1, 1, 1) assert integrate(Quaternion(x, x, x, x), x) == \ Quaternion(x**2 / 2, x**2 / 2, x**2 / 2, x**2 / 2) assert Quaternion.rotate_point((1, 1, 1), q1) == (1 / 5, 1, 7 / 5)
def test_should_construct_from_screw(self): l = (0, 0, 1) m = (0, -x, 0) dq = DualQuaternion.from_screw(l, m, theta, 0) assert dq.real == Quaternion(cos(theta * S.Half), 0, 0, sin(theta * S.Half)) assert dq.dual == Quaternion(0, 0, -x * sin(theta * S.Half), 0)
def test_Quaternion_str_printer(): q = Quaternion(x, y, z, t) assert str(q) == "x + y*i + z*j + t*k" q = Quaternion(x,y,z,x*t) assert str(q) == "x + y*i + z*j + t*x*k" q = Quaternion(x,y,z,x+t) assert str(q) == "x + y*i + z*j + (t + x)*k"
def test_quaternion_conversions(): q1 = Quaternion(1, 2, 3, 4) assert q1.to_axis_angle() == ((2 * sqrt(29)/29, 3 * sqrt(29)/29, 4 * sqrt(29)/29), 2 * acos(sqrt(30)/30)) assert q1.to_rotation_matrix() == Matrix([[-S(2)/3, S(2)/15, S(11)/15], [S(2)/3, -S(1)/3, S(2)/3], [S(1)/3, S(14)/15, S(2)/15]]) assert q1.to_rotation_matrix((1, 1, 1)) == Matrix([[-S(2)/3, S(2)/15, S(11)/15, S(4)/5], [S(2)/3, -S(1)/3, S(2)/3, S(0)], [S(1)/3, S(14)/15, S(2)/15, -S(2)/5], [S(0), S(0), S(0), S(1)]]) theta = symbols("theta", real=True) q2 = Quaternion(cos(theta/2), 0, 0, sin(theta/2)) assert trigsimp(q2.to_rotation_matrix()) == Matrix([ [cos(theta), -sin(theta), 0], [sin(theta), cos(theta), 0], [0, 0, 1]]) assert q2.to_axis_angle() == ((0, 0, sin(theta/2)/Abs(sin(theta/2))), 2*acos(cos(theta/2))) assert trigsimp(q2.to_rotation_matrix((1, 1, 1))) == Matrix([ [cos(theta), -sin(theta), 0, sin(theta) - cos(theta) + 1], [sin(theta), cos(theta), 0, -sin(theta) - cos(theta) + 1], [0, 0, 1, 0], [0, 0, 0, 1]])
def test_quaternion_conversions(): q1 = Quaternion(1, 2, 3, 4) assert q1.to_axis_angle() == ((2 * sqrt(29)/29, 3 * sqrt(29)/29, 4 * sqrt(29)/29), 2 * acos(sqrt(30)/30)) assert q1.to_rotation_matrix() == Matrix([[Rational(-2, 3), Rational(2, 15), Rational(11, 15)], [Rational(2, 3), Rational(-1, 3), Rational(2, 3)], [Rational(1, 3), Rational(14, 15), Rational(2, 15)]]) assert q1.to_rotation_matrix((1, 1, 1)) == Matrix([[Rational(-2, 3), Rational(2, 15), Rational(11, 15), Rational(4, 5)], [Rational(2, 3), Rational(-1, 3), Rational(2, 3), S.Zero], [Rational(1, 3), Rational(14, 15), Rational(2, 15), Rational(-2, 5)], [S.Zero, S.Zero, S.Zero, S.One]]) theta = symbols("theta", real=True) q2 = Quaternion(cos(theta/2), 0, 0, sin(theta/2)) assert trigsimp(q2.to_rotation_matrix()) == Matrix([ [cos(theta), -sin(theta), 0], [sin(theta), cos(theta), 0], [0, 0, 1]]) assert q2.to_axis_angle() == ((0, 0, sin(theta/2)/Abs(sin(theta/2))), 2*acos(cos(theta/2))) assert trigsimp(q2.to_rotation_matrix((1, 1, 1))) == Matrix([ [cos(theta), -sin(theta), 0, sin(theta) - cos(theta) + 1], [sin(theta), cos(theta), 0, -sin(theta) - cos(theta) + 1], [0, 0, 1, 0], [0, 0, 0, 1]])
def __new__(cls, p=Quaternion(0), q=Quaternion(0)): if not isinstance(p, Quaternion): p = Quaternion(p) if not isinstance(q, Quaternion): q = Quaternion(q) obj = Expr.__new__(cls, p, q) obj._p = p obj._q = q return obj
def test_quaternion_rotation_iss1593(): """ There was a sign mistake in the definition, of the rotation matrix. This tests that particular sign mistake. See issue 1593 for reference. See wikipedia https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#Quaternion-derived_rotation_matrix for the correct definition """ q = Quaternion(cos(phi / 2), sin(phi / 2), 0, 0) assert (trigsimp(q.to_rotation_matrix()) == Matrix( [[1, 0, 0], [0, cos(phi), -sin(phi)], [0, sin(phi), cos(phi)]]))
def test_quaternion_conversions(): q1 = Quaternion(1, 2, 3, 4) assert q1.to_axis_angle() == ((2 * sqrt(29)/29, 3 * sqrt(29)/29, 4 * sqrt(29)/29), 2 * acos(sqrt(30)/30)) assert q1.to_rotation_matrix() == Matrix([[-S(2)/3, S(2)/15, S(11)/15], [S(2)/3, -S(1)/3, S(14)/15], [S(1)/3, S(14)/15, S(2)/15]]) assert q1.to_rotation_matrix((1, 1, 1)) == Matrix([[-S(2)/3, S(2)/15, S(11)/15, S(4)/5], [S(2)/3, -S(1)/3, S(14)/15, -S(4)/15], [S(1)/3, S(14)/15, S(2)/15, -S(2)/5], [S(0), S(0), S(0), S(1)]]) theta = symbols("theta", real=True) q2 = Quaternion(cos(theta/2), 0, 0, sin(theta/2)) assert trigsimp(q2.to_rotation_matrix()) == Matrix([ [cos(theta), -sin(theta), 0], [sin(theta), cos(theta), 0], [0, 0, 1]]) assert q2.to_axis_angle() == ((0, 0, sin(theta/2)/Abs(sin(theta/2))), 2*acos(cos(theta/2))) assert trigsimp(q2.to_rotation_matrix((1, 1, 1))) == Matrix([ [cos(theta), -sin(theta), 0, sin(theta) - cos(theta) + 1], [sin(theta), cos(theta), 0, -sin(theta) - cos(theta) + 1], [0, 0, 1, 0], [0, 0, 0, 1]])
def test_quaternion_rotation_iss1593(): """ There was a sign mistake in the definition, of the rotation matrix. This tests that particular sign mistake. See issue 1593 for reference. See wikipedia https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#Quaternion-derived_rotation_matrix for the correct definition """ q = Quaternion(cos(x/2), sin(x/2), 0, 0) assert(trigsimp(q.to_rotation_matrix()) == Matrix([ [1, 0, 0], [0, cos(x), -sin(x)], [0, sin(x), cos(x)]]))
def test_quaternion_axis_angle(): test_data = [ # axis, angle, expected_quaternion ((1, 0, 0), 0, (1, 0, 0, 0)), ((1, 0, 0), pi/2, (sqrt(2)/2, sqrt(2)/2, 0, 0)), ((0, 1, 0), pi/2, (sqrt(2)/2, 0, sqrt(2)/2, 0)), ((0, 0, 1), pi/2, (sqrt(2)/2, 0, 0, sqrt(2)/2)), ((1, 0, 0), pi, (0, 1, 0, 0)), ((0, 1, 0), pi, (0, 0, 1, 0)), ((0, 0, 1), pi, (0, 0, 0, 1)), ((1, 1, 1), pi, (0, 1/sqrt(3),1/sqrt(3),1/sqrt(3))), ((sqrt(3)/3, sqrt(3)/3, sqrt(3)/3), pi*2/3, (S.Half, S.Half, S.Half, S.Half)) ] for axis, angle, expected in test_data: assert Quaternion.from_axis_angle(axis, angle) == Quaternion(*expected)
def rotated(self, nx: float, ny: float, nz: float, theta: float): """ Returns a rotated version of this object :param nx: x-component of the rotation axis :param ny: y-component of the rotation axis :param nz: z-component of the rotation axis :param theta: rotation angle :return: a rotated version of this object """ nrm = N(sqrt(nx**2 + ny**2 + nz**2)) sn2 = N(sin(theta / 2)) cs2 = N(cos(theta / 2)) q = Quaternion(cs2, sn2 * nx / nrm, sn2 * ny / nrm, sn2 * nz / nrm) q_inv = q.conjugate() r = q_inv * Quaternion(0, x, y, z) * q return Geometry3D(self.subs_3d(self.f, r.b, r.c, r.d))
def rotate_around_axis(self, axis, angle): transform_matrix = Quaternion.from_axis_angle( (axis[0], axis[1], axis[2]), angle).to_rotation_matrix( (self.center[0], self.center[1], self.center[2])) for i in range(8): p = self.points[i] spp = sp.Point3D(p[0], p[1], p[2]) spp = spp.transform(transform_matrix) self.points[i] = [spp.x.evalf(), spp.y.evalf(), spp.z.evalf()]
def test_issue_16318(): #for rtruediv q0 = Quaternion(0, 0, 0, 0) raises(ValueError, lambda: 1/q0) #for rotate_point q = Quaternion(1, 2, 3, 4) (axis, angle) = q.to_axis_angle() assert Quaternion.rotate_point((1, 1, 1), (axis, angle)) == (S.One / 5, 1, S(7) / 5) #test for to_axis_angle q = Quaternion(-1, 1, 1, 1) axis = (-sqrt(3)/3, -sqrt(3)/3, -sqrt(3)/3) angle = 2*pi/3 assert (axis, angle) == q.to_axis_angle()
def test_quaternion_construction(): q = Quaternion(x, y, z, w) assert q + q == Quaternion(2*x, 2*y, 2*z, 2*w) q2 = Quaternion.from_axis_angle((sqrt(3)/3, sqrt(3)/3, sqrt(3)/3), 2*pi/3) assert q2 == Quaternion(Rational(1, 2), Rational(1, 2), Rational(1, 2), Rational(1, 2)) M = Matrix([[cos(x), -sin(x), 0], [sin(x), cos(x), 0], [0, 0, 1]]) q3 = trigsimp(Quaternion.from_rotation_matrix(M)) assert q3 == Quaternion(sqrt(2)*sqrt(cos(x) + 1)/2, 0, 0, sqrt(-2*cos(x) + 2)/2) nc = Symbol('nc', commutative=False) raises(ValueError, lambda: Quaternion(x, y, nc, w))
def test_quaternion_construction(): q = Quaternion(x, y, z, w) assert q + q == Quaternion(2*x, 2*y, 2*z, 2*w) q2 = Quaternion.from_axis_angle((sqrt(3)/3, sqrt(3)/3, sqrt(3)/3), 2*pi/3) assert q2 == Quaternion(Rational(1/2), Rational(1/2), Rational(1/2), Rational(1,2)) M = Matrix([[cos(x), -sin(x), 0], [sin(x), cos(x), 0], [0, 0, 1]]) q3 = trigsimp(Quaternion.from_rotation_matrix(M)) assert q3 == Quaternion(sqrt(2)*sqrt(cos(x) + 1)/2, 0, 0, sqrt(-2*cos(x) + 2)/2)
def test_quaternion_construction(): q = Quaternion(w, x, y, z) assert q + q == Quaternion(2*w, 2*x, 2*y, 2*z) q2 = Quaternion.from_axis_angle((sqrt(3)/3, sqrt(3)/3, sqrt(3)/3), pi*Rational(2, 3)) assert q2 == Quaternion(S.Half, S.Half, S.Half, S.Half) M = Matrix([[cos(phi), -sin(phi), 0], [sin(phi), cos(phi), 0], [0, 0, 1]]) q3 = trigsimp(Quaternion.from_rotation_matrix(M)) assert q3 == Quaternion(sqrt(2)*sqrt(cos(phi) + 1)/2, 0, 0, sqrt(2 - 2*cos(phi))*sign(sin(phi))/2) nc = Symbol('nc', commutative=False) raises(ValueError, lambda: Quaternion(w, x, nc, z))
def transform_point(pin, t): """Returns the coordinates of the point pin(a 3 tuple) after transformation. Parameters ========== pin : tuple A 3-element tuple of coordinates of a point which needs to be transformed. r : DualQuaternion Screw axis and dual angle of rotation. Returns ======= tuple The coordinates of the point after transformation. """ pout = (t * DualQuaternion(1, Quaternion(0, *pin)) * t.combined_conjugate()).dual return (pout.b, pout.c, pout.d)
def rotate_face(self, fid): connected_edges = [ self.get_connected_edge(self.faces[fid][i], fid) for i in range(4) ] # rotate face plane around random axis with origin at face centre plane = self.face2plane(fid) origin = self.face_centre(fid) axis = plane.random_point() - plane.random_point() transform_matrix = Quaternion.from_axis_angle((axis[0], axis[1], axis[2]), random.uniform(-self.max_angle_offset, self.max_angle_offset) )\ .to_rotation_matrix((origin[0], origin[1], origin[2])) norm = sp.Point3D(plane.normal_vector) plane = sp.Plane(origin, normal_vector=norm.transform(transform_matrix)) # find new points for face new_face_points = [] for ce in connected_edges: line = sp.Line3D(sp.Point3D(self.points[ce[0]]), sp.Point3D(self.points[ce[1]])) new_point = plane.intersection(line)[0] new_point = [ new_point.x.evalf(), new_point.y.evalf(), new_point.z.evalf() ] new_face_points.append(new_point) if not self.is_b_not_far_than_a(self.points[ce[0]], self.points[ce[1]], new_point): print("skip face rotating - hex will not be valid") return # replace old points with new for i in range(4): pid = self.faces[fid][i] self.points[pid] = new_face_points[i]
def test_quaternion_complex_real_addition(): a = symbols("a", complex=True) b = symbols("b", real=True) # This symbol is not complex: c = symbols("c", commutative=False) q = Quaternion(w, x, y, z) assert a + q == Quaternion(w + re(a), x + im(a), y, z) assert 1 + q == Quaternion(1 + w, x, y, z) assert I + q == Quaternion(w, 1 + x, y, z) assert b + q == Quaternion(w + b, x, y, z) raises(ValueError, lambda: c + q) raises(ValueError, lambda: q * c) raises(ValueError, lambda: c * q) assert -q == Quaternion(-w, -x, -y, -z) q1 = Quaternion(3 + 4*I, 2 + 5*I, 0, 7 + 8*I, real_field = False) q2 = Quaternion(1, 4, 7, 8) assert q1 + (2 + 3*I) == Quaternion(5 + 7*I, 2 + 5*I, 0, 7 + 8*I) assert q2 + (2 + 3*I) == Quaternion(3, 7, 7, 8) assert q1 * (2 + 3*I) == \ Quaternion((2 + 3*I)*(3 + 4*I), (2 + 3*I)*(2 + 5*I), 0, (2 + 3*I)*(7 + 8*I)) assert q2 * (2 + 3*I) == Quaternion(-10, 11, 38, -5) q1 = Quaternion(1, 2, 3, 4) q0 = Quaternion(0, 0, 0, 0) assert q1 + q0 == q1 assert q1 - q0 == q1 assert q1 - q1 == q0
def test_quaternion_axis_angle_simplification(): result = Quaternion.from_axis_angle((1, 2, 3), asin(4)) assert result.a == cos(asin(4)/2) assert result.b == sqrt(14)*sin(asin(4)/2)/14 assert result.c == sqrt(14)*sin(asin(4)/2)/7 assert result.d == 3*sqrt(14)*sin(asin(4)/2)/14
import sympy as sp from sympy.algebras.quaternion import Quaternion """ Remember! This assumes r i j k and not i j k r """ pi = sp.symbols('myvar') q = Quaternion(0, 1, 0, 0).normalize() omega = sp.Matrix([0, pi, 0]) omega_quat = Quaternion(0, *omega) q_dot = (1 / 2) * q * omega_quat print(q_dot)
def test_quaternion_nultiplication(): q1 = Quaternion(3 + 4 * I, 2 + 5 * I, 0, 7 + 8 * I, real_field=False) q2 = Quaternion(1, 2, 3, 5) q3 = Quaternion(1, 1, 1, y) assert Quaternion._generic_mul(4, 1) == 4 assert Quaternion._generic_mul(4, q1) == Quaternion(12 + 16 * I, 8 + 20 * I, 0, 28 + 32 * I) assert q2.mul(2) == Quaternion(2, 4, 6, 10) assert q2.mul(q3) == Quaternion(-5 * y - 4, 3 * y - 2, 9 - 2 * y, y + 4) assert q2.mul(q3) == q2 * q3
def test_quaternion_multiplication(): q1 = Quaternion(3 + 4*I, 2 + 5*I, 0, 7 + 8*I, real_field = False) q2 = Quaternion(1, 2, 3, 5) q3 = Quaternion(1, 1, 1, y) assert Quaternion._generic_mul(4, 1) == 4 assert Quaternion._generic_mul(4, q1) == Quaternion(12 + 16*I, 8 + 20*I, 0, 28 + 32*I) assert q2.mul(2) == Quaternion(2, 4, 6, 10) assert q2.mul(q3) == Quaternion(-5*y - 4, 3*y - 2, 9 - 2*y, y + 4) assert q2.mul(q3) == q2*q3 z = symbols('z', complex=True) z_quat = Quaternion(re(z), im(z), 0, 0) q = Quaternion(*symbols('q:4', real=True)) assert z * q == z_quat * q assert q * z == q * z_quat
#!/usr/bin/env python3 from sympy import * from sympy.algebras.quaternion import Quaternion import sys var("q0 q1 q2 q3 p0 p1 p2 p3 i j k x y z yz xz psi phi") #Q = Quaternion(q0, 0, 0, q3) #P = Quaternion(p0, p1, 0, 0) Q = Quaternion(q0, 0, 0, q3) P = Quaternion(p0, p1, 0, 0) Qs = conjugate(Q) Ps = conjugate(P) #pprint(Qs) R = P*Q ee = (R)*Quaternion(0,0,1,0)*conjugate(R) #a = (P)*Quaternion(0,0,1,0)*conjugate(P) e = ee.a + ee.b * i + ee.c * j + ee.d * k #pprint(simplify(a)) pprint(simplify(e)) #eee = solve(Eq(2*p1*sqrt(1-p1), z), (p1)) #pprint(eee) #pprint(solve(Eq(4*q0**4 - 4*yz*q0**2 - xz**2), (q0))) Q = Quaternion(cos(phi/2), x*sin(phi/2), y*sin(phi/2), 0)
def test_quaternion_functions(): q = Quaternion(w, x, y, z) q1 = Quaternion(1, 2, 3, 4) q0 = Quaternion(0, 0, 0, 0) assert conjugate(q) == Quaternion(w, -x, -y, -z) assert q.norm() == sqrt(w**2 + x**2 + y**2 + z**2) assert q.normalize() == Quaternion(w, x, y, z) / sqrt(w**2 + x**2 + y**2 + z**2) assert q.inverse() == Quaternion(w, -x, -y, -z) / (w**2 + x**2 + y**2 + z**2) assert q.inverse() == q.pow(-1) raises(ValueError, lambda: q0.inverse()) assert q.pow(2) == Quaternion(w**2 - x**2 - y**2 - z**2, 2 * w * x, 2 * w * y, 2 * w * z) assert q**(2) == Quaternion(w**2 - x**2 - y**2 - z**2, 2 * w * x, 2 * w * y, 2 * w * z) assert q1.pow(-2) == Quaternion(Rational(-7, 225), Rational(-1, 225), Rational(-1, 150), Rational(-2, 225)) assert q1**(-2) == Quaternion(Rational(-7, 225), Rational(-1, 225), Rational(-1, 150), Rational(-2, 225)) assert q1.pow(-0.5) == NotImplemented raises(TypeError, lambda: q1**(-0.5)) assert q1.exp() == \ Quaternion(E * cos(sqrt(29)), 2 * sqrt(29) * E * sin(sqrt(29)) / 29, 3 * sqrt(29) * E * sin(sqrt(29)) / 29, 4 * sqrt(29) * E * sin(sqrt(29)) / 29) assert q1._ln() == \ Quaternion(log(sqrt(30)), 2 * sqrt(29) * acos(sqrt(30)/30) / 29, 3 * sqrt(29) * acos(sqrt(30)/30) / 29, 4 * sqrt(29) * acos(sqrt(30)/30) / 29) assert q1.pow_cos_sin(2) == \ Quaternion(30 * cos(2 * acos(sqrt(30)/30)), 60 * sqrt(29) * sin(2 * acos(sqrt(30)/30)) / 29, 90 * sqrt(29) * sin(2 * acos(sqrt(30)/30)) / 29, 120 * sqrt(29) * sin(2 * acos(sqrt(30)/30)) / 29) assert diff(Quaternion(x, x, x, x), x) == Quaternion(1, 1, 1, 1) assert integrate(Quaternion(x, x, x, x), x) == \ Quaternion(x**2 / 2, x**2 / 2, x**2 / 2, x**2 / 2) assert Quaternion.rotate_point((1, 1, 1), q1) == (S.One / 5, 1, S(7) / 5) n = Symbol('n') raises(TypeError, lambda: q1**n) n = Symbol('n', integer=True) raises(TypeError, lambda: q1**n) assert Quaternion(22, 23, 55, 8).scalar_part() == 22 assert Quaternion(w, x, y, z).scalar_part() == w assert Quaternion(22, 23, 55, 8).vector_part() == Quaternion(0, 23, 55, 8) assert Quaternion(w, x, y, z).vector_part() == Quaternion(0, x, y, z) assert q1.axis() == Quaternion(0, 2 * sqrt(29) / 29, 3 * sqrt(29) / 29, 4 * sqrt(29) / 29) assert q1.axis().pow(2) == Quaternion(-1, 0, 0, 0) assert q0.axis().scalar_part() == 0 assert q.axis() == Quaternion(0, x / sqrt(x**2 + y**2 + z**2), y / sqrt(x**2 + y**2 + z**2), z / sqrt(x**2 + y**2 + z**2)) assert q0.is_pure() == True assert q1.is_pure() == False assert Quaternion(0, 0, 0, 3).is_pure() == True assert Quaternion(0, 2, 10, 3).is_pure() == True assert Quaternion(w, 2, 10, 3).is_pure() == None assert q1.angle() == atan(sqrt(29)) assert q.angle() == atan2(sqrt(x**2 + y**2 + z**2), w) assert Quaternion.arc_coplanar(q1, Quaternion(2, 4, 6, 8)) == True assert Quaternion.arc_coplanar(q1, Quaternion(1, -2, -3, -4)) == True assert Quaternion.arc_coplanar(q1, Quaternion(1, 8, 12, 16)) == True assert Quaternion.arc_coplanar(q1, Quaternion(1, 2, 3, 4)) == True assert Quaternion.arc_coplanar(q1, Quaternion(w, 4, 6, 8)) == True assert Quaternion.arc_coplanar(q1, Quaternion(2, 7, 4, 1)) == False assert Quaternion.arc_coplanar(q1, Quaternion(w, x, y, z)) == None raises(ValueError, lambda: Quaternion.arc_coplanar(q1, q0)) assert Quaternion.vector_coplanar(Quaternion(0, 8, 12, 16), Quaternion(0, 4, 6, 8), Quaternion(0, 2, 3, 4)) == True assert Quaternion.vector_coplanar(Quaternion(0, 0, 0, 0), Quaternion(0, 4, 6, 8), Quaternion(0, 2, 3, 4)) == True assert Quaternion.vector_coplanar(Quaternion(0, 8, 2, 6), Quaternion(0, 1, 6, 6), Quaternion(0, 0, 3, 4)) == False assert Quaternion.vector_coplanar(Quaternion(0, 1, 3, 4), Quaternion(0, 4, w, 6), Quaternion(0, 6, 8, 1)) == None raises(ValueError, lambda: Quaternion.vector_coplanar(q0, Quaternion(0, 4, 6, 8), q1)) assert Quaternion(0, 1, 2, 3).parallel(Quaternion(0, 2, 4, 6)) == True assert Quaternion(0, 1, 2, 3).parallel(Quaternion(0, 2, 2, 6)) == False assert Quaternion(0, 1, 2, 3).parallel(Quaternion(w, x, y, 6)) == None raises(ValueError, lambda: q0.parallel(q1)) assert Quaternion(0, 1, 2, 3).orthogonal(Quaternion(0, -2, 1, 0)) == True assert Quaternion(0, 2, 4, 7).orthogonal(Quaternion(0, 2, 2, 6)) == False assert Quaternion(0, 2, 4, 7).orthogonal(Quaternion(w, x, y, 6)) == None raises(ValueError, lambda: q0.orthogonal(q1)) assert q1.index_vector() == Quaternion(0, 2 * sqrt(870) / 29, 3 * sqrt(870) / 29, 4 * sqrt(870) / 29) assert Quaternion(0, 3, 9, 4).index_vector() == Quaternion(0, 3, 9, 4) assert Quaternion(4, 3, 9, 4).mensor() == log(sqrt(122)) assert Quaternion(3, 3, 0, 2).mensor() == log(sqrt(22)) assert q0.is_zero_quaternion() == True assert q1.is_zero_quaternion() == False assert Quaternion(w, 0, 0, 0).is_zero_quaternion() == None
def test_quaternion_functions(): q = Quaternion(x, y, z, w) q1 = Quaternion(1, 2, 3, 4) q0 = Quaternion(0, 0, 0, 0) assert conjugate(q) == Quaternion(x, -y, -z, -w) assert q.norm() == sqrt(w**2 + x**2 + y**2 + z**2) assert q.normalize() == Quaternion(x, y, z, w) / sqrt(w**2 + x**2 + y**2 + z**2) assert q.inverse() == Quaternion(x, -y, -z, -w) / (w**2 + x**2 + y**2 + z**2) raises(ValueError, lambda: q0.inverse()) assert q.pow(2) == Quaternion(-w**2 + x**2 - y**2 - z**2, 2*x*y, 2*x*z, 2*w*x) assert q1.pow(-2) == Quaternion(-S(7)/225, -S(1)/225, -S(1)/150, -S(2)/225) assert q1.pow(-0.5) == NotImplemented assert q1.exp() == \ Quaternion(E * cos(sqrt(29)), 2 * sqrt(29) * E * sin(sqrt(29)) / 29, 3 * sqrt(29) * E * sin(sqrt(29)) / 29, 4 * sqrt(29) * E * sin(sqrt(29)) / 29) assert q1._ln() == \ Quaternion(log(sqrt(30)), 2 * sqrt(29) * acos(sqrt(30)/30) / 29, 3 * sqrt(29) * acos(sqrt(30)/30) / 29, 4 * sqrt(29) * acos(sqrt(30)/30) / 29) assert q1.pow_cos_sin(2) == \ Quaternion(30 * cos(2 * acos(sqrt(30)/30)), 60 * sqrt(29) * sin(2 * acos(sqrt(30)/30)) / 29, 90 * sqrt(29) * sin(2 * acos(sqrt(30)/30)) / 29, 120 * sqrt(29) * sin(2 * acos(sqrt(30)/30)) / 29) assert diff(Quaternion(x, x, x, x), x) == Quaternion(1, 1, 1, 1) assert integrate(Quaternion(x, x, x, x), x) == \ Quaternion(x**2 / 2, x**2 / 2, x**2 / 2, x**2 / 2) assert Quaternion.rotate_point((1, 1, 1), q1) == (1 / 5, 1, 7 / 5)
def test_quaternion_functions(): q = Quaternion(x, y, z, w) q1 = Quaternion(1, 2, 3, 4) assert conjugate(q) == Quaternion(x, -y, -z, -w) assert q.norm() == sqrt(w**2 + x**2 + y**2 + z**2) assert q.normalize() == Quaternion(x, y, z, w) / sqrt(w**2 + x**2 + y**2 + z**2) assert q.inverse() == Quaternion(x, -y, -z, -w) / (w**2 + x**2 + y**2 + z**2) assert q.pow(2) == Quaternion(-w**2 + x**2 - y**2 - z**2, 2 * x * y, 2 * x * z, 2 * w * x) assert q1.exp() == \ Quaternion(E * cos(sqrt(29)), 2 * sqrt(29) * E * sin(sqrt(29)) / 29, 3 * sqrt(29) * E * sin(sqrt(29)) / 29, 4 * sqrt(29) * E * sin(sqrt(29)) / 29) assert q1._ln() == \ Quaternion(log(sqrt(30)), 2 * sqrt(29) * acos(sqrt(30)/30) / 29, 3 * sqrt(29) * acos(sqrt(30)/30) / 29, 4 * sqrt(29) * acos(sqrt(30)/30) / 29) assert q1.pow_cos_sin(2) == \ Quaternion(30 * cos(2 * acos(sqrt(30)/30)), 60 * sqrt(29) * sin(2 * acos(sqrt(30)/30)) / 29, 90 * sqrt(29) * sin(2 * acos(sqrt(30)/30)) / 29, 120 * sqrt(29) * sin(2 * acos(sqrt(30)/30)) / 29) assert diff(Quaternion(x, x, x, x), x) == Quaternion(1, 1, 1, 1) assert integrate(Quaternion(x, x, x, x), x) == \ Quaternion(x**2 / 2, x**2 / 2, x**2 / 2, x**2 / 2) assert Quaternion.rotate_point((1, 1, 1), q1) == (1 / 5, 1, 7 / 5)
def test_quaternion_complex_real_addition(): a = symbols("a", complex=True) b = symbols("b", real=True) # This symbol is not complex: c = symbols("c", commutative=False) q = Quaternion(x, y, z, w) assert a + q == Quaternion(x + re(a), y + im(a), z, w) assert 1 + q == Quaternion(1 + x, y, z, w) assert I + q == Quaternion(x, 1 + y, z, w) assert b + q == Quaternion(x + b, y, z, w) assert c + q == Add(c, Quaternion(x, y, z, w), evaluate=False) assert q * c == Mul(Quaternion(x, y, z, w), c, evaluate=False) assert c * q == Mul(c, Quaternion(x, y, z, w), evaluate=False) assert -q == Quaternion(-x, -y, -z, -w) q1 = Quaternion(3 + 4 * I, 2 + 5 * I, 0, 7 + 8 * I, real_field=False) q2 = Quaternion(1, 4, 7, 8) assert q1 + (2 + 3 * I) == Quaternion(5 + 7 * I, 2 + 5 * I, 0, 7 + 8 * I) assert q2 + (2 + 3 * I) == Quaternion(3, 7, 7, 8) assert q1 * (2 + 3*I) == \ Quaternion((2 + 3*I)*(3 + 4*I), (2 + 3*I)*(2 + 5*I), 0, (2 + 3*I)*(7 + 8*I)) assert q2 * (2 + 3 * I) == Quaternion(-10, 11, 38, -5)
def quaternion_derivative(quaterion, omega): omega_quat = Quaternion(0, *omega) q_dot = (1/2) * quaterion * omega_quat return [getattr(q_dot, field) for field in 'abcd']
def test_quaternion_evalf(): assert Quaternion(sqrt(2), 0, 0, sqrt(3)).evalf() == Quaternion(sqrt(2).evalf(), 0, 0, sqrt(3).evalf()) assert Quaternion(1/sqrt(2), 0, 0, 1/sqrt(2)).evalf() == Quaternion((1/sqrt(2)).evalf(), 0, 0, (1/sqrt(2)).evalf())
import sympy as sym from sympy.algebras.quaternion import Quaternion c0 = sym.sqrt(3) q = Quaternion(2, c0, c0, c0) p = (1, 2, -3) pp = Quaternion.rotate_point((1, 2, -3), q) print(q) print(p) print(pp) print(q * Quaternion(0, 1, 2, -3))
def test_quaternion_functions(): q = Quaternion(w, x, y, z) q1 = Quaternion(1, 2, 3, 4) q0 = Quaternion(0, 0, 0, 0) assert conjugate(q) == Quaternion(w, -x, -y, -z) assert q.norm() == sqrt(w**2 + x**2 + y**2 + z**2) assert q.normalize() == Quaternion(w, x, y, z) / sqrt(w**2 + x**2 + y**2 + z**2) assert q.inverse() == Quaternion(w, -x, -y, -z) / (w**2 + x**2 + y**2 + z**2) assert q.inverse() == q.pow(-1) raises(ValueError, lambda: q0.inverse()) assert q.pow(2) == Quaternion(w**2 - x**2 - y**2 - z**2, 2*w*x, 2*w*y, 2*w*z) assert q**(2) == Quaternion(w**2 - x**2 - y**2 - z**2, 2*w*x, 2*w*y, 2*w*z) assert q1.pow(-2) == Quaternion(Rational(-7, 225), Rational(-1, 225), Rational(-1, 150), Rational(-2, 225)) assert q1**(-2) == Quaternion(Rational(-7, 225), Rational(-1, 225), Rational(-1, 150), Rational(-2, 225)) assert q1.pow(-0.5) == NotImplemented raises(TypeError, lambda: q1**(-0.5)) assert q1.exp() == \ Quaternion(E * cos(sqrt(29)), 2 * sqrt(29) * E * sin(sqrt(29)) / 29, 3 * sqrt(29) * E * sin(sqrt(29)) / 29, 4 * sqrt(29) * E * sin(sqrt(29)) / 29) assert q1._ln() == \ Quaternion(log(sqrt(30)), 2 * sqrt(29) * acos(sqrt(30)/30) / 29, 3 * sqrt(29) * acos(sqrt(30)/30) / 29, 4 * sqrt(29) * acos(sqrt(30)/30) / 29) assert q1.pow_cos_sin(2) == \ Quaternion(30 * cos(2 * acos(sqrt(30)/30)), 60 * sqrt(29) * sin(2 * acos(sqrt(30)/30)) / 29, 90 * sqrt(29) * sin(2 * acos(sqrt(30)/30)) / 29, 120 * sqrt(29) * sin(2 * acos(sqrt(30)/30)) / 29) assert diff(Quaternion(x, x, x, x), x) == Quaternion(1, 1, 1, 1) assert integrate(Quaternion(x, x, x, x), x) == \ Quaternion(x**2 / 2, x**2 / 2, x**2 / 2, x**2 / 2) assert Quaternion.rotate_point((1, 1, 1), q1) == (S.One / 5, 1, S(7) / 5) n = Symbol('n') raises(TypeError, lambda: q1**n) n = Symbol('n', integer=True) raises(TypeError, lambda: q1**n)
def test_quaternion_functions(): q = Quaternion(x, y, z, w) q1 = Quaternion(1, 2, 3, 4) q0 = Quaternion(0, 0, 0, 0) assert conjugate(q) == Quaternion(x, -y, -z, -w) assert q.norm() == sqrt(w**2 + x**2 + y**2 + z**2) assert q.normalize() == Quaternion(x, y, z, w) / sqrt(w**2 + x**2 + y**2 + z**2) assert q.inverse() == Quaternion(x, -y, -z, -w) / (w**2 + x**2 + y**2 + z**2) raises(ValueError, lambda: q0.inverse()) assert q.pow(2) == Quaternion(-w**2 + x**2 - y**2 - z**2, 2 * x * y, 2 * x * z, 2 * w * x) assert q1.pow(-2) == Quaternion(-S(7) / 225, -S(1) / 225, -S(1) / 150, -S(2) / 225) assert q1.pow(-0.5) == NotImplemented assert q1.exp() == \ Quaternion(E * cos(sqrt(29)), 2 * sqrt(29) * E * sin(sqrt(29)) / 29, 3 * sqrt(29) * E * sin(sqrt(29)) / 29, 4 * sqrt(29) * E * sin(sqrt(29)) / 29) assert q1._ln() == \ Quaternion(log(sqrt(30)), 2 * sqrt(29) * acos(sqrt(30)/30) / 29, 3 * sqrt(29) * acos(sqrt(30)/30) / 29, 4 * sqrt(29) * acos(sqrt(30)/30) / 29) assert q1.pow_cos_sin(2) == \ Quaternion(30 * cos(2 * acos(sqrt(30)/30)), 60 * sqrt(29) * sin(2 * acos(sqrt(30)/30)) / 29, 90 * sqrt(29) * sin(2 * acos(sqrt(30)/30)) / 29, 120 * sqrt(29) * sin(2 * acos(sqrt(30)/30)) / 29) assert diff(Quaternion(x, x, x, x), x) == Quaternion(1, 1, 1, 1) assert integrate(Quaternion(x, x, x, x), x) == \ Quaternion(x**2 / 2, x**2 / 2, x**2 / 2, x**2 / 2) assert Quaternion.rotate_point((1, 1, 1), q1) == (1 / 5, 1, 7 / 5)