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_angle_to(): a = Quaternion() b = Quaternion().set_from_euler(Euler(0, pi, 0)) c = Quaternion().set_from_euler(Euler(0, pi * 2, 0)) assert a.angle_to(a) == 0 assert a.angle_to(b) == pi assert a.angle_to(c) == 0
def test_set_from_euler_set_from_quaternion(): angles = [Vector3(1, 0, 0), Vector3(0, 1, 0), Vector3(0, 0, 1)] # ensure euler conversion to/from Quaternion matches. for i in range(len(orders)): for j in range(len(angles)): eulers2 = Euler().set_from_quaternion( Quaternion().set_from_euler( Euler(angles[j].x, angles[j].y, angles[j].z, orders[i])), orders[i], ) new_angle = Vector3(eulers2.x, eulers2.y, eulers2.z) assert new_angle.distance_to(angles[j]) < 0.001
def test_set_from_vector3_to_vector3(): a = Euler() a.set(0, 1, 0, Euler.RotationOrders.ZYX) assert a.equals(euler_azyx) assert not a.equals(euler_axyz) assert not a.equals(euler_zero) vec = Vector3(0, 1, 0) b = Euler().set_from_vector3(vec, Euler.RotationOrders.ZYX) assert a.equals(b) c = b.to_vector3() assert c.equals(vec)
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
def test_quaternion_set_from_euler_euler_from_quaternion(): test_values = [euler_zero, euler_axyz, euler_azyx] for i in range(len(test_values)): v = test_values[i] q = Quaternion().set_from_euler(v) v2 = Euler().set_from_quaternion(q, v.order) q2 = Quaternion().set_from_euler(v2) assert quat_equals(q, q2)
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_apply_euler(): a = Vector3(x, y, z) euler = Euler(90, -45, 0) expected = Vector3(-2.352970120501014, -4.7441750936226645, 0.9779234597246458) a.apply_euler(euler) 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_update_matrix_world(): root = WorldObject() root.position.set(-5, 8, 0) root.rotation.set_from_euler(Euler(pi / 4, 0, 0)) root.update_matrix() child1 = WorldObject() child1.position.set(0, 0, 5) root.add(child1) child2 = WorldObject() child2.rotation.set_from_euler(Euler(0, -pi / 4, 0)) child1.add(child2) objs = [root, child1, child2] assert all(obj.matrix_world_dirty for obj in objs) # test both updating parents and children child1.update_matrix_world(update_parents=True) assert all(not obj.matrix_world_dirty for obj in objs) p = Vector3(10, 10, 10) p.apply_matrix4(child2.matrix) p.apply_matrix4(child1.matrix) p.apply_matrix4(root.matrix) x = Vector3(10, 10, 10) x.apply_matrix4(child2.matrix_world) # if there is a difference it's a floating point error assert Vector3().sub_vectors(p, x).length() < 0.00000000001 # reorganize such that child1 and 2 become siblings child1.remove(child2) root.add(child2) assert not child1.matrix_world_dirty # child2 should be flagged as dirty again now assert child2.matrix_world_dirty
def test_gimbal_local_quat(): # known problematic quaternions q1 = Quaternion(0.5207769385244341, -0.4783214164122354, 0.520776938524434, 0.47832141641223547) # q2 = Quaternion( # 0.11284905712620674, # 0.6980437630368944, # -0.11284905712620674, # 0.6980437630368944, # ) euler_order = Euler.RotationOrders.ZYX # create Euler directly from a Quaternion e_via_q1 = Euler().set_from_quaternion( q1, euler_order) # there is likely a bug here # create Euler from Quaternion via an intermediate Matrix4 m_via_q1 = Matrix4().make_rotation_from_quaternion(q1) e_via_m_via_q1 = Euler().set_from_rotation_matrix(m_via_q1, euler_order) # the results here are different assert euler_equals(e_via_q1, e_via_m_via_q1) # this result is correcy
def test_update_matrix(): root = WorldObject() root.position.set(3, 6, 8) root.scale.set(1, 1.2, 1) root.rotation.set_from_euler(Euler(pi / 2, 0, 0)) root.update_matrix() t, r, s = Vector3(), Quaternion(), Vector3() root.matrix.decompose(t, r, s) assert t == root.position # todo: do somehting like np.allclose # assert r == root.rotation # close, but not quite the same # assert s == root.scale assert root.matrix_world_dirty
def test_from_array(): a = Euler() array = [x, y, z] a.from_array(array) assert a.x == x, "No order: check x" assert a.y == y, "No order: check y" assert a.z == z, "No order: check z" assert a.order == Euler.RotationOrders.XYZ, "No order: check order" a = Euler() array = [x, y, z, Euler.RotationOrders.ZXY] a.from_array(array) assert a.x == x, "With order: check x" assert a.y == y, "With order: check y" assert a.z == z, "With order: check z" assert a.order == Euler.RotationOrders.ZXY, "With order: check order"
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_rotate_towards(): a = Quaternion() b = Quaternion().set_from_euler(Euler(0, pi, 0)) c = Quaternion() half_pi = pi * 0.5 a.rotate_towards(b, 0) assert a.equals(a) is True a.rotate_towards(b, pi * 2) # test overshoot assert a.equals(b) is True a.set(0, 0, 0, 1) a.rotate_towards(b, half_pi) assert a.angle_to(c) - half_pi <= eps
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_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_to_array(): order = Euler.RotationOrders.YXZ a = Euler(x, y, z, order) array = a.to_array() assert array[0] == x, "No array, no offset: check x" assert array[1] == y, "No array, no offset: check y" assert array[2] == z, "No array, no offset: check z" assert array[3] == order, "No array, no offset: check order" array = [] a.to_array(array) assert array[0] == x, "With array, no offset: check x" assert array[1] == y, "With array, no offset: check y" assert array[2] == z, "With array, no offset: check z" assert array[3] == order, "With array, no offset: check order" array = [] a.to_array(array, 1) assert array[0] is None, "With array and offset: check [0]" assert array[1] == x, "With array and offset: check x" assert array[2] == y, "With array and offset: check y" assert array[3] == z, "With array and offset: check z" assert array[4] == order, "With array and offset: check order"
def test_order(): a = Euler() assert a.order == Euler.DefaultOrder a = Euler(1, 2, 3) assert a.order == Euler.DefaultOrder a = Euler(4, 5, 6, Euler.RotationOrders.YZX) assert a.order == Euler.RotationOrders.YZX a = Euler(7, 8, 9, Euler.RotationOrders.YZX) a.order = Euler.RotationOrders.ZXY assert a.order == Euler.RotationOrders.ZXY a = Euler(11, 12, 13, Euler.RotationOrders.YZX) a.order = Euler.RotationOrders.ZXY assert a.order == Euler.RotationOrders.ZXY
def test_z(): a = Euler() assert a.z == 0 a = Euler(1, 2, 3) assert a.z == 3 a = Euler(4, 5, 6, Euler.RotationOrders.XYZ) assert a.z == 6 a = Euler(7, 8, 9, Euler.RotationOrders.XYZ) a.z = 10 assert a.z == 10 a = Euler(11, 12, 13, Euler.RotationOrders.XYZ) a.z = 14 assert a.z == 14
def test_y(): a = Euler() assert a.y == 0 a = Euler(1, 2, 3) assert a.y == 2 a = Euler(4, 5, 6, Euler.RotationOrders.XYZ) assert a.y == 5 a = Euler(7, 8, 9, Euler.RotationOrders.XYZ) a.y = 10 assert a.y == 10 a = Euler(11, 12, 13, Euler.RotationOrders.XYZ) a.y = 14 assert a.y == 14
def test_x(): a = Euler() assert a.x == 0 a = Euler(1, 2, 3) assert a.x == 1 a = Euler(4, 5, 6, Euler.RotationOrders.XYZ) assert a.x == 4 a = Euler(7, 8, 9, Euler.RotationOrders.XYZ) a.x = 10 assert a.x == 10 a = Euler(11, 12, 13, Euler.RotationOrders.XYZ) a.x = 14 assert a.x == 14
def test_instancing(): a = Euler() assert a.equals(euler_zero) assert not a.equals(euler_axyz) assert not a.equals(euler_azyx)
) x = 2 y = 3 z = 4 w = 5 eps = 0.0001 orders = [ Euler.RotationOrders.XYZ, Euler.RotationOrders.YXZ, Euler.RotationOrders.ZXY, Euler.RotationOrders.ZYX, Euler.RotationOrders.YZX, Euler.RotationOrders.XZY, ] euler_angles = Euler(0.1, -0.3, 0.25) def q_sub(a, b): result = a.clone() result.x -= b.x result.y -= b.y result.z -= b.z result.w -= b.w return result def change_euler_order(euler, order): return Euler(euler.x, euler.y, euler.z, order)
from pygfx.linalg import ( Vector3, Euler, Matrix4, Quaternion, ) from utils import matrix_equals, euler_equals, quat_equals x = 2 y = 3 z = 4 w = 5 euler_zero = Euler(0, 0, 0, Euler.RotationOrders.XYZ) euler_axyz = Euler(1, 0, 0, Euler.RotationOrders.XYZ) euler_azyx = Euler(0, 1, 0, Euler.RotationOrders.ZYX) # INSTANCING def test_instancing(): a = Euler() assert a.equals(euler_zero) assert not a.equals(euler_axyz) assert not a.equals(euler_azyx) # PROPERTIES STUFF def test_x(): a = Euler() assert a.x == 0
def change_euler_order(euler, order): return Euler(euler.x, euler.y, euler.z, order)