def test_make_rotation_x(): a = Matrix4() b = sqrt(3) / 2 c = Matrix4().set(1, 0, 0, 0, 0, b, -0.5, 0, 0, 0.5, b, 0, 0, 0, 0, 1) a.make_rotation_x(pi / 6) assert matrix_equals(a, c)
def test_make_translation(): a = Matrix4() b = Vector3(2, 3, 4) c = Matrix4().set(1, 0, 0, 2, 0, 1, 0, 3, 0, 0, 1, 4, 0, 0, 0, 1) a.make_translation(b.x, b.y, b.z) assert matrix_equals(a, c)
def test_make_rotation_axis(): axis = Vector3(1.5, 0.0, 1.0).normalize() rads = radians(45) a = Matrix4().make_rotation_axis(axis, rads) expected = Matrix4().set( 0.9098790095958609, -0.39223227027636803, 0.13518148560620882, 0, 0.39223227027636803, 0.7071067811865476, -0.588348405414552, 0, 0.13518148560620882, 0.588348405414552, 0.7972277715906868, 0, 0, 0, 0, 1, ) assert matrix_equals(a, expected), "Check numeric result"
def test_make_orthographic(): a = Matrix4().make_orthographic(-1, 1, -1, 1, 1, 100) expected = Matrix4().set( 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -2 / 99, -101 / 99, 0, 0, 0, 1 ) assert matrix_equals(a, expected), "Check result"
def test_scale(): a = Matrix4().set(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) b = Vector3(2, 3, 4) c = Matrix4().set(2, 6, 12, 4, 10, 18, 28, 8, 18, 30, 44, 12, 26, 42, 60, 16) a.scale(b) assert matrix_equals(a, c)
def test_set_position(): a = Matrix4().set(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) b = Vector3(-1, -2, -3) c = Matrix4().set(0, 1, 2, -1, 4, 5, 6, -2, 8, 9, 10, -3, 12, 13, 14, 15) a.set_position(b) assert matrix_equals(a, c)
def test_composedecompose(): t_values = [ Vector3(), Vector3(3, 0, 0), Vector3(0, 4, 0), Vector3(0, 0, 5), Vector3(-6, 0, 0), Vector3(0, -7, 0), Vector3(0, 0, -8), Vector3(-2, 5, -9), Vector3(-2, -5, -9), ] s_values = [ Vector3(1, 1, 1), Vector3(2, 2, 2), Vector3(1, -1, 1), Vector3(-1, 1, 1), Vector3(1, 1, -1), Vector3(2, -2, 1), Vector3(-1, 2, -2), Vector3(-1, -1, -1), Vector3(-2, -2, -2), ] r_values = [ Quaternion(), Quaternion().set_from_euler(Euler(1, 1, 0)), Quaternion().set_from_euler(Euler(1, -1, 1)), Quaternion(0, 0.9238795292366128, 0, 0.38268342717215614), ] for ti in range(len(t_values)): for si in range(len(s_values)): for ri in range(len(r_values)): t = t_values[ti] s = s_values[si] r = r_values[ri] m = Matrix4().compose(t, r, s) t2 = Vector3() r2 = Quaternion() s2 = Vector3() m.decompose(t2, r2, s2) m2 = Matrix4().compose(t2, r2, s2) ## # debug code # matrixIsSame = matrix_equals( m, m2 ) # if ( ! matrixIsSame ) { # console.log( t, s, r ) # console.log( t2, s2, r2 ) # console.log( m, m2 ) # } ## assert matrix_equals(m, m2)
def test_copy_position(): a = Matrix4().set(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) b = Matrix4().set(1, 2, 3, 0, 5, 6, 7, 0, 9, 10, 11, 0, 13, 14, 15, 16) assert not matrix_equals(a, b), "a and b initially not equal" b.copy_position(a) assert matrix_equals(a, b), "a and b equal after copy_position()"
def test_copy(): a = Matrix4().set(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) b = Matrix4().copy(a) assert matrix_equals(a, b) # ensure that it is a True copy a.elements[0] = 2 assert not matrix_equals(a, b)
def test_matrix4_set_from_euler_euler_from_rotation_matrix(): test_values = [euler_zero, euler_axyz, euler_azyx] for i in range(len(test_values)): v = test_values[i] m = Matrix4().make_rotation_from_euler(v) v2 = Euler().set_from_rotation_matrix(m, v.order) m2 = Matrix4().make_rotation_from_euler(v2) assert matrix_equals(m, m2, 0.0001)
def test_transpose(): a = Matrix4() b = a.clone().transpose() assert matrix_equals(a, b) b = Matrix4().set(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) c = b.clone().transpose() assert not matrix_equals(b, c) c.transpose() assert matrix_equals(b, c)
def test_equals(): a = Matrix4().set(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) b = Matrix4().set(0, -1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) assert not a.equals(b), "Check that a does not equal b" assert not b.equals(a), "Check that b does not equal a" a.copy(b) assert a.equals(b), "Check that a equals b after copy()" assert b.equals(a), "Check that b equals a after copy()"
def test_set_from_rotation_matrix(): # contrived examples purely to please the god of code coverage... # match conditions in various 'else [if]' blocks a = Quaternion() q = Quaternion(-9, -2, 3, -4).normalize() m = Matrix4().make_rotation_from_quaternion(q) expected = Vector4( 0.8581163303210332, 0.19069251784911848, -0.2860387767736777, 0.38138503569823695, ) a.set_from_rotation_matrix(m) assert abs(a.x - expected.x) <= eps, "m11 > m22 && m11 > m33: check x" assert abs(a.y - expected.y) <= eps, "m11 > m22 && m11 > m33: check y" assert abs(a.z - expected.z) <= eps, "m11 > m22 && m11 > m33: check z" assert abs(a.w - expected.w) <= eps, "m11 > m22 && m11 > m33: check w" q = Quaternion(-1, -2, 1, -1).normalize() m.make_rotation_from_quaternion(q) expected = Vector4( 0.37796447300922714, 0.7559289460184544, -0.37796447300922714, 0.37796447300922714, ) a.set_from_rotation_matrix(m) assert abs(a.x - expected.x) <= eps, "m22 > m33: check x" assert abs(a.y - expected.y) <= eps, "m22 > m33: check y" assert abs(a.z - expected.z) <= eps, "m22 > m33: check z" assert abs(a.w - expected.w) <= eps, "m22 > m33: check w"
def test_set_from_matrix_position(): a = Vector3() m = Matrix4().set(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53) a.set_from_matrix_position(m) assert a.x == 7, "Check x" assert a.y == 19, "Check y" assert a.z == 37, "Check z"
def test_set_from_euler_set_from_rotation_matrix(): # ensure euler conversion for Quaternion matches that of Matrix4 for i in range(len(orders)): q = Quaternion().set_from_euler( change_euler_order(euler_angles, orders[i])) m = Matrix4().make_rotation_from_euler( change_euler_order(euler_angles, orders[i])) q2 = Quaternion().set_from_rotation_matrix(m) assert q_sub(q, q2).length() < 0.001
def test_transform_direction(): a = Vector3(x, y, z) m = Matrix4() transformed = Vector3(0.3713906763541037, 0.5570860145311556, 0.7427813527082074) a.transform_direction(m) assert abs(a.x - transformed.x) <= eps, "Check x" assert abs(a.y - transformed.y) <= eps, "Check y" assert abs(a.z - transformed.z) <= eps, "Check z"
def test_set_from_matrix_scale(): a = Vector3() m = Matrix4().set(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53) expected = Vector3(25.573423705088842, 31.921779399024736, 35.70714214271425) a.set_from_matrix_scale(m) assert abs(a.x - expected.x) <= eps, "Check x" assert abs(a.y - expected.y) <= eps, "Check y" assert abs(a.z - expected.z) <= eps, "Check z"
def test_multiply_matrices(): # Reference: # # #!/usr/bin/env python # from __future__ import print_function # import numpy as np # print( # np.dot( # np.reshape([2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53], (4, 4)), # np.reshape([59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131], (4, 4)) # ) # ) # # [[ 1585 1655 1787 1861] # [ 5318 5562 5980 6246] # [10514 11006 11840 12378] # [15894 16634 17888 18710]] lhs = Matrix4().set(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53) rhs = Matrix4().set( 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131 ) ans = Matrix4() ans.multiply_matrices(lhs, rhs) assert ans.elements[0] == 1585 assert ans.elements[1] == 5318 assert ans.elements[2] == 10514 assert ans.elements[3] == 15894 assert ans.elements[4] == 1655 assert ans.elements[5] == 5562 assert ans.elements[6] == 11006 assert ans.elements[7] == 16634 assert ans.elements[8] == 1787 assert ans.elements[9] == 5980 assert ans.elements[10] == 11840 assert ans.elements[11] == 17888 assert ans.elements[12] == 1861 assert ans.elements[13] == 6246 assert ans.elements[14] == 12378 assert ans.elements[15] == 18710
def test_determinant(): a = Matrix4() assert a.determinant() == 1 a.elements[0] = 2 assert a.determinant() == 2 a.elements[0] = 0 assert a.determinant() == 0 # calculated via http://www.euclideanspace.com/maths/algebra/matrix/functions/determinant/fourD/index.htm a.set(2, 3, 4, 5, -1, -21, -3, -4, 6, 7, 8, 10, -8, -9, -10, -12) assert a.determinant() == 76
def test_look_at(): a = Matrix4() expected = Matrix4().identity() eye = Vector3(0, 0, 0) target = Vector3(0, 1, -1) up = Vector3(0, 1, 0) a.look_at(eye, target, up) rotation = Euler().set_from_rotation_matrix(a) assert rotation.x * (180 / pi) == 45, "Check the rotation" # eye and target are in the same position eye.copy(target) a.look_at(eye, target, up) assert matrix_equals(a, expected), "Check the result for eye == target" # up and z are parallel eye.set(0, 1, 0) target.set(0, 0, 0) a.look_at(eye, target, up) expected.set(1, 0, 0, 0, 0, 0.0001, 1, 0, 0, -1, 0.0001, 0, 0, 0, 0, 1) assert matrix_equals(a, expected), "Check the result for when up and z are parallel"
def test_set_from_matrix_column(): a = Vector3() m = Matrix4().set(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53) a.set_from_matrix_column(m, 0) assert a.x == 2, "Index 0: check x" assert a.y == 11, "Index 0: check y" assert a.z == 23, "Index 0: check z" a.set_from_matrix_column(m, 2) assert a.x == 5, "Index 2: check x" assert a.y == 17, "Index 2: check y" assert a.z == 31, "Index 2: check z"
def test_instancing(): a = Matrix4() assert a.determinant() == 1 b = Matrix4().set(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) assert b.elements[0] == 0 assert b.elements[1] == 4 assert b.elements[2] == 8 assert b.elements[3] == 12 assert b.elements[4] == 1 assert b.elements[5] == 5 assert b.elements[6] == 9 assert b.elements[7] == 13 assert b.elements[8] == 2 assert b.elements[9] == 6 assert b.elements[10] == 10 assert b.elements[11] == 14 assert b.elements[12] == 3 assert b.elements[13] == 7 assert b.elements[14] == 11 assert b.elements[15] == 15 assert not matrix_equals(a, b)
def test_make_rotation_from_eulerextract_rotation(): test_values = [ Euler(0, 0, 0, Euler.RotationOrders.XYZ), Euler(1, 0, 0, Euler.RotationOrders.XYZ), Euler(0, 1, 0, Euler.RotationOrders.ZYX), Euler(0, 0, 0.5, Euler.RotationOrders.YZX), Euler(0, 0, -0.5, Euler.RotationOrders.YZX), ] for i in range(len(test_values)): v = test_values[i] m = Matrix4().make_rotation_from_euler(v) v2 = Euler().set_from_rotation_matrix(m, v.order) m2 = Matrix4().make_rotation_from_euler(v2) assert matrix_equals(m, m2, eps), ( "make_rotation_from_euler #" + i + ": original and Euler-derived matrices are equal" ) assert euler_equals(v, v2, eps), ( "make_rotation_from_euler #" + i + ": original and matrix-derived Eulers are equal" ) m3 = Matrix4().extract_rotation(m2) v3 = Euler().set_from_rotation_matrix(m3, v.order) assert matrix_equals(m, m3, eps), ( "extract_rotation #" + i + ": original and extracted matrices are equal" ) assert euler_equals(v, v3, eps), ( "extract_rotation #" + i + ": original and extracted Eulers are equal" )
def test_apply_matrix4(): a = Vector3(x, y, z) b = Vector4(x, y, z, 1) m = Matrix4().make_rotation_x(pi) a.apply_matrix4(m) b.apply_matrix4(m) assert a.x == b.x / b.w assert a.y == b.y / b.w assert a.z == b.z / b.w m = Matrix4().make_translation(3, 2, 1) a.apply_matrix4(m) b.apply_matrix4(m) assert a.x == b.x / b.w assert a.y == b.y / b.w assert a.z == b.z / b.w m = Matrix4().set(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0) a.apply_matrix4(m) b.apply_matrix4(m) assert a.x == b.x / b.w assert a.y == b.y / b.w assert a.z == b.z / b.w
def test_multiply_quaternions_multiply(): angles = [Euler(1, 0, 0), Euler(0, 1, 0), Euler(0, 0, 1)] q1 = Quaternion().set_from_euler( change_euler_order(angles[0], Euler.RotationOrders.XYZ)) q2 = Quaternion().set_from_euler( change_euler_order(angles[1], Euler.RotationOrders.XYZ)) q3 = Quaternion().set_from_euler( change_euler_order(angles[2], Euler.RotationOrders.XYZ)) q = Quaternion().multiply_quaternions(q1, q2).multiply(q3) m1 = Matrix4().make_rotation_from_euler( change_euler_order(angles[0], Euler.RotationOrders.XYZ)) m2 = Matrix4().make_rotation_from_euler( change_euler_order(angles[1], Euler.RotationOrders.XYZ)) m3 = Matrix4().make_rotation_from_euler( change_euler_order(angles[2], Euler.RotationOrders.XYZ)) m = Matrix4().multiply_matrices(m1, m2).multiply(m3) q_from_m = Quaternion().set_from_rotation_matrix(m) assert q_sub(q, q_from_m).length() < 0.001
def test_identity(): b = Matrix4().set(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) assert b.elements[0] == 0 assert b.elements[1] == 4 assert b.elements[2] == 8 assert b.elements[3] == 12 assert b.elements[4] == 1 assert b.elements[5] == 5 assert b.elements[6] == 9 assert b.elements[7] == 13 assert b.elements[8] == 2 assert b.elements[9] == 6 assert b.elements[10] == 10 assert b.elements[11] == 14 assert b.elements[12] == 3 assert b.elements[13] == 7 assert b.elements[14] == 11 assert b.elements[15] == 15 a = Matrix4() assert not matrix_equals(a, b) b.identity() assert matrix_equals(a, b)
def test_to_array(): a = Matrix4().set(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) no_offset = [1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16] with_offset = [None, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16] array = a.to_array() assert array == no_offset, "No array, no offset" array = [] a.to_array(array) assert array == no_offset, "With array, no offset" array = [] a.to_array(array, 1) assert array == with_offset, "With array, with offset"
def test_make_basisextract_basis(): identity_basis = [Vector3(1, 0, 0), Vector3(0, 1, 0), Vector3(0, 0, 1)] a = Matrix4().make_basis(identity_basis[0], identity_basis[1], identity_basis[2]) identity = Matrix4() assert matrix_equals(a, identity) test_bases = [[Vector3(0, 1, 0), Vector3(-1, 0, 0), Vector3(0, 0, 1)]] for i in range(len(test_bases)): test_basis = test_bases[i] b = Matrix4().make_basis(test_basis[0], test_basis[1], test_basis[2]) out_basis = [Vector3(), Vector3(), Vector3()] b.extract_basis(out_basis[0], out_basis[1], out_basis[2]) # check what goes in, is what comes out. for j in range(len(out_basis)): assert out_basis[j].equals(test_basis[j]) # get the basis out the hard war for j in range(len(identity_basis)): out_basis[j].copy(identity_basis[j]) out_basis[j].apply_matrix4(b) # did the multiply method of basis extraction work? for j in range(len(out_basis)): assert out_basis[j].equals(test_basis[j])
def test_premultiply(): lhs = Matrix4().set(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53) rhs = Matrix4().set( 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131 ) rhs.premultiply(lhs) assert rhs.elements[0] == 1585 assert rhs.elements[1] == 5318 assert rhs.elements[2] == 10514 assert rhs.elements[3] == 15894 assert rhs.elements[4] == 1655 assert rhs.elements[5] == 5562 assert rhs.elements[6] == 11006 assert rhs.elements[7] == 16634 assert rhs.elements[8] == 1787 assert rhs.elements[9] == 5980 assert rhs.elements[10] == 11840 assert rhs.elements[11] == 17888 assert rhs.elements[12] == 1861 assert rhs.elements[13] == 6246 assert rhs.elements[14] == 12378 assert rhs.elements[15] == 18710
def test_multiply_vector3(): angles = [Euler(1, 0, 0), Euler(0, 1, 0), Euler(0, 0, 1)] # ensure euler conversion for Quaternion matches that of Matrix4 for i in range(len(orders)): for j in range(len(angles)): q = Quaternion().set_from_euler( change_euler_order(angles[j], orders[i])) m = Matrix4().make_rotation_from_euler( change_euler_order(angles[j], orders[i])) v0 = Vector3(1, 0, 0) qv = v0.clone().apply_quaternion(q) mv = v0.clone().apply_matrix4(m) assert qv.distance_to(mv) < 0.001