added unit tests

This commit is contained in:
FatalErr42O 2024-11-30 21:04:33 -08:00
parent 2c7a244aa2
commit f8b83a8450
3 changed files with 386 additions and 0 deletions

View File

@ -0,0 +1,147 @@
local cos = math.cos
local sin = math.sin
local m = mtul.math
local mat4 = mtul.math.mat4
local pitch_ZY = function(a)
local temp = mat4.new()
temp[6] = cos(a)
temp[7] = sin(a)
temp[10] = -sin(a)
temp[11] = cos(a)
return temp
end
local pitch_ZY2 = function(a)
local temp = mat4.new()
temp[6] = cos(a)
temp[7] = -sin(a)
temp[10] = sin(a)
temp[11] = cos(a)
return temp
end
local roll_XY = function(a)
local temp = mat4.new()
temp[1] = cos(a)
temp[2] = sin(a)
temp[5] = -sin(a)
temp[6] = cos(a)
return temp
end
local roll_XY2 = function(a)
local temp = mat4.new()
temp[1] = cos(a)
temp[2] = -sin(a)
temp[5] = sin(a)
temp[6] = cos(a)
return temp
end
local yaw_ZX = function(a)
local temp = mat4.new()
temp[1] = cos(a)
temp[3] = -sin(a)
temp[9] = sin(a)
temp[11] = cos(a)
return temp
end
local yaw_ZX2 = function(a)
local temp = mat4.new()
temp[1] = cos(a)
temp[3] = sin(a)
temp[9] = -sin(a)
temp[11] = cos(a)
return temp
end
local pitch_transforms = {
pitch = pitch_ZY,
pitch_cw = pitch_ZY2,
}
local roll_transforms = {
roll = roll_XY,
roll_cw = roll_XY2
}
local yaw_transforms = {
yaw = yaw_ZX,
yaw_cw = yaw_ZX2
}
local possible_orders = {
{1,2,3},
{1,3,2},
{2,3,1},
{2,1,3},
{3,2,1},
{3,1,2}
}
local matrix_tolerance = .00001
local function check_matrix_equality(m1,m2)
for i = 1,16 do
if math.abs(m1[i]-m2[i]) > 0.001 then
return false
end
end
return true
end
local function make_funcs_human_readable(str)
for i, v in pairs(pitch_transforms) do
str=string.gsub(str, tostring(v), i)
end
for i, v in pairs(roll_transforms) do
str=string.gsub(str, tostring(v), i )
end
for i, v in pairs(yaw_transforms) do
str=string.gsub(str, tostring(v), i)
end
return str
end
function mtul.math.find_matrix_rotation_order(check_func)
--x,y,z
local euler = {(math.random()-.5)*math.pi*4, (math.random()-.5)*math.pi*4, (math.random()-.5)*math.pi*4}
local output = check_func(mat4.new(), euler[1],euler[2],euler[3])
local iter = 0
local running_order
for _, p_tf in pairs(pitch_transforms) do
for _, y_tf in pairs(yaw_transforms) do
for _, r_tf in pairs(roll_transforms) do
--now that we have every combination, get every order of every combination. this is disusting by the way.
for _, order in pairs(possible_orders) do
iter = iter + 1
--intrinsic order is pitch yaw roll for this check, meaning that 1 is assigned to pitch and so fourth.
local matrices = {p_tf, y_tf, r_tf}
local active_mat = mat4.new()
running_order = nil
for i=1,3 do
local func = matrices[order[i]]
running_order = (running_order and running_order .." * "..tostring(func)) or tostring(func)
active_mat = active_mat*func(euler[order[i]])
end
--print("#"..iter, make_funcs_human_readable(running_order))
if check_matrix_equality(output, active_mat) then
print(make_funcs_human_readable(running_order))
--return true
end
end
end
end
end
return running_order
end
print("================== BEGINNING LUANTI AND IRRLICHT UNIT TESTs =======================")
local find_rot_order = mtul.math.find_matrix_rotation_order
print("\n checking sanity of tests:")
local _tempeuler = {(math.random()-.5)*math.pi*4, (math.random()-.5)*math.pi*4, (math.random()-.5)*math.pi*4}
local _testmatrix = mtul.math.mat4.set_rot_zxy(mat4.new(), _tempeuler[1],_tempeuler[2],_tempeuler[3])
print("matrix equality check func is sane:", check_matrix_equality(_testmatrix,_testmatrix))
print("matrix equality check func tolerance:", matrix_tolerance)
print("\n Checking rotation orders. Rotation application order is in reverse, these are the literal matrix multiplication order. ")
print("checking rotation matrix `set_rot_luanti_entity`")
find_rot_order(mtul.math.mat4.set_rot_luanti_entity)
print("checking `set_rot_irrlicht_bone`")
find_rot_order(mtul.math.mat4.set_rot_irrlicht_bone)
print("================== ENDING LUANTI AND IRRLICHT UNIT TESTs =======================")

View File

@ -0,0 +1,115 @@
local mat4 = mtul.math.mat4
local matrix_tolerance = .00001
local function check_matrix_equality(m1,m2)
for i = 1,16 do
if math.abs(m1[i]-m2[i]) > 0.001 then
return false
end
end
return true
end
local tau = math.pi*2
local function santitize_angle(a)
if a > tau then
local co = math.floor(math.abs(a/tau))
a = a-(co*tau)
end
if a < 0 then
local co = math.ceil(math.abs(a/tau))
a = a+(co*tau)
end
return a
end
local function equals(a,b)
if math.abs(a-b) < .0001 then
return true
else
return false
end
end
local function santitize_angles_unpack(x,y,z)
return santitize_angle(x), santitize_angle(y), santitize_angle(z)
end
--[[for i=1,10 do
find_irr_order()
end]]
print("================== BEGINNING MATRIX UNIT TESTs =======================")
local find_rot_order = mtul.math.find_matrix_rotation_order
print("\n checking sanity of tests:")
local _tempeuler = {(math.random()-.5)*math.pi*4, (math.random()-.5)*math.pi*4, (math.random()-.5)*math.pi*4}
local _testmatrix = mtul.math.mat4.set_rot_zxy(mat4.new(), _tempeuler[1],_tempeuler[2],_tempeuler[3])
print("matrix equality check func is sane:", check_matrix_equality(_testmatrix,_testmatrix))
print("matrix equality check func tolerance:", matrix_tolerance)
local ran_ang = math.random()*math.pi*2
print("santitize_angle is sane:", equals(1.60947655802, santitize_angle(7.8926618652)), equals(ran_ang, santitize_angle(ran_ang-tau)))
--print("checking irrlicht setRotationRadians")
--print(find_rot_order(irrlicht_matrix_setRotationRadians).." iterations")
print("\n checking MTUL's luanti and irrlicht matrix rotation orders. Rotation application order is in reverse, these are the literal matrix multiplication order. ")
print("checking rotation matrix `set_rot_luanti_entity`")
find_rot_order(mtul.math.mat4.set_rot_luanti_entity)
print("checking `set_rot_irrlicht_bone`")
find_rot_order(mtul.math.mat4.set_rot_irrlicht_bone)
--[[print("check in euler out euler for minetest entitiy matrix rotations")
local x,y,z =(math.random()-.5)*math.pi*4,(math.random()-.5)*math.pi*4,(math.random()-.5)*math.pi*4
local new_mat = mat4.set_rot_luanti_entity(mat4.new(), x,y,z)
print(santitize_angles_unpack(x,y,z))
print(santitize_angles_unpack(new_mat:get_rot_luanti_entity()))]]
--============================ ENTITY MATRICES =======================================
--random check to see if angles output correctly
print("\n Checking to euler and out euler. Verifying that `matrix1` and `matrix2` matches in `euler->matrix1->euler?->matrix2` for the following euler conversions")
local x,y,z = math.random()*math.pi*2, math.random()*math.pi*2, math.random()*math.pi*2
local new_mat = mat4.set_rot_luanti_entity(mat4.new(), x,y,z)
local x2,y2,z2 = new_mat:get_rot_luanti_entity()
print("luanti_entity (random angle) matrices are equivelant: ", check_matrix_equality(new_mat, mat4.set_rot_luanti_entity(mat4.new(), x2,y2,z2)))
--repeat for irrlicht bones
x,y,z = math.random()*math.pi*2, math.random()*math.pi*2, math.random()*math.pi*2
new_mat = mat4.set_rot_irrlicht_bone(mat4.identity(), x,y,z)
x2,y2,z2 = new_mat:get_rot_irrlicht_bone()
print("irrlicht_bone (random angle) matrices are equivelant: ", check_matrix_equality(new_mat, mat4.set_rot_irrlicht_bone(mat4.new(), x2,y2,z2)))
print("\n Checking edge cases for euler (where gimbal lock occours)")
--check if edge cases work properly
x,y,z = math.pi/2, math.random()*math.pi*2, math.random()*math.pi*2
new_mat = mat4.set_rot_luanti_entity(mat4.identity(), x,y,z)
x2,y2,z2 = new_mat:get_rot_luanti_entity()
print("luanti_entity matrices are equivelant at `x=math.pi/2 or -math.pi/2:` ", check_matrix_equality(new_mat, mat4.set_rot_luanti_entity(mat4.new(), x2,y2,z2)))
--check if edge cases work properly
x,y,z = math.random()*math.pi*2, math.pi/2, math.random()*math.pi*2
new_mat = mat4.set_rot_irrlicht_bone(mat4.new(), x,y,z)
x2,y2,z2 = new_mat:get_rot_irrlicht_bone()
-- euler1->matrix->euler2; check euler1==euler2
print("irrlicht_bone matrices are equivelant at `y=math.pi/2 or -math.pi/2`: ", check_matrix_equality(new_mat, mat4.set_rot_irrlicht_bone(mat4.new(), x2,y2,z2)))
print("\n==================== END OF MATRIX UNIT TESTs =============================")
--[[local m00 = new_mat[1]
local m12 = new_mat[7]
local m22 =
local m02 = , , new_mat[11]
x = math.atan2(m12, m22);
y = math.atan2(-m02, math.sqrt(1.0 - m02 * m02));
z = math.atan2(m01, m00);
print()]]
--[[local quat = mtul.math.quat
print("\n comparing `euler to matrix` & `euler to quaternion` matrix outputs")
x,y,z = math.random()*math.pi*2, math.random()*math.pi*2, math.random()*math.pi*2
local mat1 = mat4.set_rot_zxy(mat4.new(), x,y,z)
local new_quat = quat.new():from_euler_zxy(x,y,z)
local mat2 = mat4.set_rot_from_quaternion(mat4.new(), new_quat)
--local new_quat = mtul.quat.from_euler_
print(mat1)
print(mat2)
print(check_matrix_equality(mat1,mat2))]]

View File

@ -0,0 +1,124 @@
local mat4 = mtul.math.mat4
local quat = mtul.math.quat
local vec3 = mtul.math.vec3
local function check_matrix_equality(m1,m2)
for i = 1,16 do
if math.abs(m1[i]-m2[i]) > 0.001 then
return false
end
end
return true
end
print("================== BEGINNING QUATERNION UNIT TESTs =======================")
--print("\n comparing mul_vec3 and rotate_vec3 with random quat on forward facing unit dir")
--[[local new_quat = mtul.math.quat.from_angle_axis((math.random()-.5)*math.pi*4, mtul.math.vec3.new(math.random(), math.random(), math.random())):normalize()
local forward = vec3.new(0,0,1)
print(new_quat:mul_vec3(forward))
print(new_quat:rotate_vec3(forward))
print("identity quat:")
new_quat = quat.new(0,0,0,1)
print(new_quat:mul_vec3(forward))
print(new_quat:rotate_vec3(forward))]]
local new_quat = mtul.math.quat.from_angle_axis((math.random()-.5)*math.pi*4, mtul.math.vec3.new(math.random(), math.random(), math.random())):normalize()
local to_mat_from_quat = mtul.math.mat4.from_quaternion(new_quat)
local to_mat_from_axis_from_quat = mat4.from_angle_axis(new_quat:to_angle_axis())
--should tell us that quat to matrix is working fine... trusting the original creators anyway...
print("\n comparing `quat->matrix` to old `quat->angle_axis->matrix`. Matches:",
check_matrix_equality(
to_mat_from_quat, --new mthod which generates a matrix
to_mat_from_axis_from_quat --old CPML method of from quaternion that just hooks through angle axis
)
)
if not check_matrix_equality(to_mat_from_quat, to_mat_from_axis_from_quat) then
print(to_mat_from_quat)
print(to_mat_from_axis_from_quat)
end
--double check (I dont trust the old method of converting to axis angle.)
local x = vec3.new(1,0,0); x=new_quat:mul_vec3(x)
local y = vec3.new(0,1,0); y=new_quat:mul_vec3(y)
local z = vec3.new(0,0,1); z=new_quat:mul_vec3(z)
local rotated_mat = mat4.new({ --this probably is confusing, each row her is a column.
x.x, x.y, x.z, 0,
y.x, y.y, y.z, 0,
z.x, z.y, z.z, 0,
0, 0, 0, 1
})
local equal = check_matrix_equality(rotated_mat, to_mat_from_quat)
print("comparing matrix generated from rotating basis vectors to `quat->matrix`. Matches:", equal)
if not equal then
print(to_mat_from_quat)
print(rotated_mat)
end
x,y,z = math.random()*math.pi*2, math.random()*math.pi*2, math.random()*math.pi*2
local matrix1 = mat4.set_rot_irrlicht_bone(mat4.identity(), x,y,z) --sample random matrix, what it is shouldn't matter as long as its special orthogonal (aka a rotation matrix)
new_quat = mat4.to_quaternion(matrix1) --this is the independent variable in which we are testing- wether this code works.
local matrix2 = mat4.from_quaternion(new_quat)
print("checking `matrix1=matrix2` in `matrix1->quaternion->matrix2`. Matches:", check_matrix_equality(matrix1, matrix2))
if not check_matrix_equality(matrix1, matrix2) then
print(matrix1)
print(matrix2)
end
print("\n checking euler functions")
x,y,z = math.random()*math.pi*2, math.random()*math.pi*2, math.random()*math.pi*2
matrix1 = mat4.set_rot_luanti_entity(mat4.identity(), x,y,z)
new_quat = quat.from_matrix(matrix1)
local x2,y2,z2 = new_quat:get_euler_luanti_entity()
matrix2 = mat4.set_rot_luanti_entity(mat4.identity(), x2,y2,z2)
print("(quat->euler) checking `matrix1=matrix2` in `euler->matrix1->quat->euler->matrix2 (ZXY/luanti entity)`. Matrices match:", check_matrix_equality(matrix1, matrix2))
if not check_matrix_equality(matrix1, matrix2) then
print(matrix1)
print(matrix2)
print(x,y,z)
print(x2,y2,z2)
end
x,y,z = math.random()*math.pi*2, math.random()*math.pi*2, math.random()*math.pi*2
matrix1 = mat4.set_rot_irrlicht_bone(mat4.identity(), x,y,z)
new_quat = quat.from_matrix(matrix1)
x2,y2,z2 = new_quat:get_euler_irrlicht_bone()
matrix2 = mat4.set_rot_irrlicht_bone(mat4.identity(), x2,y2,z2)
print("(quat->euler) checking `matrix1=matrix2` in `euler->matrix1->quat->euler->matrix2 (XYZ/irrlicht bone)`. Matrices match:", check_matrix_equality(matrix1, matrix2))
if not check_matrix_equality(matrix1, matrix2) then
print(matrix1)
print(matrix2)
print(x,y,z)
print(x2,y2,z2)
end
x,y,z = math.random()*math.pi*2, math.random()*math.pi*2, math.random()*math.pi*2
matrix2 = mat4.set_rot_luanti_entity(mat4.identity(), x,y,z)
new_quat = quat.from_euler_luanti_entity(x,y,z)
matrix1 = mat4.from_quaternion(new_quat)
print("(euler->quat) checking `matrix1=matrix2` in `euler->quat->matrix1, euler->matrix2 (ZXY/luanti entity)`, Matches:", check_matrix_equality(matrix1, matrix2))
if not check_matrix_equality(matrix1, matrix2) then
print(x,y,z)
print(matrix1)
print(matrix2)
end
x,y,z = math.random()*math.pi*2, math.random()*math.pi*2, math.random()*math.pi*2
matrix2 = mat4.set_rot_irrlicht_bone(mat4.identity(), x,y,z)
new_quat = quat.from_euler_irrlicht_bone(x,y,z)
matrix1 = mat4.from_quaternion(new_quat)
print("(euler->quat) checking `matrix1=matrix2` in `euler->quat->matrix1, euler->matrix2 (XYZ/irrlicht bone)`, Matches:", check_matrix_equality(matrix1, matrix2))
if not check_matrix_equality(matrix1, matrix2) then
print(x,y,z)
print(matrix1)
print(matrix2)
end
print("(eulur->quat->euler)")
print("\n==================== END OF QUATERNION UNIT TESTs =============================")