Added quaternion tests

* Fixed an issue with is_quat, is_vec3, is_vec2, and is_mat4 methods
* Fixed a minor issue with local variables being declared too late
This commit is contained in:
karai17 2016-07-21 20:04:32 -03:00
parent 78b34590c5
commit 5f7a7f29fa
8 changed files with 319 additions and 74 deletions

View File

@ -1,9 +1,10 @@
--- Color utilities
-- @module color
local modules = (...):gsub('%.[^%.]+$', '') .. "."
local utils = require(modules .. "utils")
local color = {}
local modules = (...):gsub('%.[^%.]+$', '') .. "."
local utils = require(modules .. "utils")
local color = {}
local color_mt = {}
local function new(r, g, b, a)
return setmetatable({ r, g, b, a }, color)
@ -258,7 +259,6 @@ function color.to_string(a)
return string.format("[ %3.0f, %3.0f, %3.0f, %3.0f ]", a[1], a[2], a[3], a[4])
end
local color_mt = {}
color_mt.__index = color
color_mt.__tostring = color.to_string

View File

@ -11,6 +11,7 @@ local sin = math.sin
local tan = math.tan
local rad = math.rad
local mat4 = {}
local mat4_mt = {}
-- Private constructor.
local function new(m)
@ -480,7 +481,11 @@ function mat4.unproject(win, view, projection, viewport)
end
function mat4.is_mat4(a)
if not type(a) == "table" and not type(a) == "cdata" then
if type(a) == "cdata" then
return ffi.istype("cpml_mat4", a)
end
if type(a) ~= "table" then
return false
end
@ -623,7 +628,6 @@ function mat4.to_frustum(a, infinite)
return frustum
end
local mat4_mt = {}
mat4_mt.__index = mat4
mat4_mt.__tostring = mat4.to_string

View File

@ -17,6 +17,7 @@ local max = math.max
local sqrt = math.sqrt
local pi = math.pi
local quat = {}
local quat_mt = {}
-- Private constructor.
local function new(x, y, z, w)
@ -25,9 +26,6 @@ local function new(x, y, z, w)
return setmetatable(q, quat_mt)
end
quat.unit = new(0, 0, 0, 1)
quat.zero = new(0, 0, 0, 0)
-- Statically allocate a temporary variable used in some of our functions.
local tmp = new(0, 0, 0, 0)
@ -269,7 +267,7 @@ end
function quat.lerp(out, a, b, s)
return out
:sub(b, a)
:mul(out, s)
:scale(out, s)
:add(a, out)
:normalize(out)
end
@ -305,24 +303,6 @@ function quat.slerp(out, a, b, s)
:add(tmp, out)
end
--- Return the imaginary part of the quaternion as a vec3.
-- @tparam vec3 out
-- @tparam quat a
-- @treturn vec3 out
function quat.imaginary(out, a)
out.x = a.x
out.y = a.y
out.z = a.z
return out
end
--- Return the real part of a quaternion.
-- @tparam quat a
-- @treturn number real
function quat.real(a)
return a.w
end
--- Unpack a quaternion into form x,y,z,w.
-- @tparam quat a
-- @treturn number x
@ -355,7 +335,8 @@ function quat.to_angle_axis(a)
return angle, vec3(x, y, z)
end
function quat.to_vec3(out, a)
function quat.to_vec3(a)
local out = vec3()
out.x = a.x
out.y = a.y
out.z = a.z
@ -373,11 +354,12 @@ end
-- @param q object to be tested
-- @treturn boolean
function quat.is_quat(a)
if type(a) == "cdata" then
return ffi.istype("cpml_quat", a)
end
return
(
type(a) == "table" or
type(a) == "cdata"
) and
type(a) == "table" and
type(a.x) == "number" and
type(a.y) == "number" and
type(a.z) == "number" and
@ -403,12 +385,11 @@ function quat.is_imaginary(a)
return a.w == 0
end
local quat_mt = {}
quat_mt.__index = quat
quat_mt.__tostring = quat.to_string
function quat_mt.__call(_, x, y, z, w)
return new(x, y, z, w)
return quat.new(x, y, z, w)
end
function quat_mt.__unm(a)
@ -435,7 +416,7 @@ end
function quat_mt.__mul(a, b)
assert(quat.is_quat(a), "__mul: Wrong argument type for left hand operant. (<cpml.quat> expected)")
assert(quat.is_quat(b) or vec3.is_vec3(b) or type(b) == "number", "__mul: Wrong argument type for right hand operant. (<cpml.quat> or <cpml.vec3> expected)")
assert(quat.is_quat(b) or vec3.is_vec3(b) or type(b) == "number", "__mul: Wrong argument type for right hand operant. (<cpml.quat> or <cpml.vec3> or <number> expected)")
if quat.is_quat(b) then
return new():mul(a, b)
@ -450,7 +431,7 @@ end
function quat_mt.__pow(a, n)
assert(quat.is_quat(a), "__pow: Wrong argument type for left hand operant. (<cpml.quat> expected)")
assert(type(b) == "number", "__pow: Wrong argument type for right hand operant. (<number> expected)")
assert(type(n) == "number", "__pow: Wrong argument type for right hand operant. (<number> expected)")
return new():pow(a, n)
end
@ -458,4 +439,7 @@ if status then
ffi.metatype(new, quat_mt)
end
quat.unit = new(0, 0, 0, 1)
quat.zero = new(0, 0, 0, 0)
return setmetatable({}, quat_mt)

View File

@ -1,11 +1,12 @@
--- A 2 component vector.
-- @module vec2
local atan2 = math.atan2
local sqrt = math.sqrt
local cos = math.cos
local sin = math.sin
local vec2 = {}
local atan2 = math.atan2
local sqrt = math.sqrt
local cos = math.cos
local sin = math.sin
local vec2 = {}
local vec2_mt = {}
-- Private constructor.
local function new(x, y)
@ -14,10 +15,6 @@ local function new(x, y)
return setmetatable(v, vec2_mt)
end
vec2.unit_x = new(1, 0)
vec2.unit_y = new(0, 1)
vec2.zero = new(0, 0)
-- Do the check to see if JIT is enabled. If so use the optimized FFI structs.
local status, ffi
if type(jit) == "table" and jit.status() then
@ -28,6 +25,10 @@ if type(jit) == "table" and jit.status() then
end
end
vec2.unit_x = new(1, 0)
vec2.unit_y = new(0, 1)
vec2.zero = new(0, 0)
--- The public constructor.
-- @param x Can be of three types: </br>
-- number x component
@ -222,11 +223,12 @@ end
-- @param v the object to be tested
-- @treturn boolean
function vec2.is_vec2(a)
if type(a) == "cdata" then
return ffi.istype("cpml_vec2", a)
end
return
(
type(a) == "table" or
type(a) == "cdata"
) and
type(a) == "table" and
type(a.x) == "number" and
type(a.y) == "number"
end
@ -253,7 +255,6 @@ function vec2.to_string(a)
return string.format("(%+0.3f,%+0.3f)", a.x, a.y)
end
local vec2_mt = {}
vec2_mt.__index = vec2
vec2_mt.__tostring = vec2.to_string

View File

@ -1,10 +1,11 @@
--- A 3 component vector.
-- @module vec3
local sqrt = math.sqrt
local cos = math.cos
local sin = math.sin
local vec3 = {}
local sqrt = math.sqrt
local cos = math.cos
local sin = math.sin
local vec3 = {}
local vec3_mt = {}
-- Private constructor.
local function new(x, y, z)
@ -13,11 +14,6 @@ local function new(x, y, z)
return setmetatable(v, vec3_mt)
end
vec3.unit_x = new(1, 0, 0)
vec3.unit_y = new(0, 1, 0)
vec3.unit_z = new(0, 0, 1)
vec3.zero = new(0, 0, 0)
-- Do the check to see if JIT is enabled. If so use the optimized FFI structs.
local status, ffi
if type(jit) == "table" and jit.status() then
@ -28,6 +24,11 @@ if type(jit) == "table" and jit.status() then
end
end
vec3.unit_x = new(1, 0, 0)
vec3.unit_y = new(0, 1, 0)
vec3.unit_z = new(0, 0, 1)
vec3.zero = new(0, 0, 0)
-- Statically allocate a temporary variable used in some of our functions.
local tmp = new(0, 0, 0)
@ -248,12 +249,12 @@ end
-- @param v the object to be tested
-- @treturn boolean
function vec3.is_vec3(a)
return
(
type(a) == "table" or
type(a) == "cdata"
if type(a) == "cdata" then
return ffi.istype("cpml_vec3", a)
end
) and
return
type(a) == "table" and
type(a.x) == "number" and
type(a.y) == "number" and
type(a.z) == "number"
@ -273,7 +274,6 @@ function vec3.to_string(a)
return string.format("(%+0.3f,%+0.3f,%+0.3f)", a.x, a.y, a.z)
end
local vec3_mt = {}
vec3_mt.__index = vec3
vec3_mt.__tostring = vec3.to_string

View File

@ -2,3 +2,30 @@ local mat4 = require "modules.mat4"
describe("mat4:", function()
end)
--[[
new
identity
from_angle_axis
from_direction
from_transform
from_ortho
from_perspective
from_hmd_perspective
clone
mul
mul_mat4x1
invert
scale
rotate
translate
shear
look_at
transpose
project
unproject
is_mat4
to_vec4s
to_quat
to_frustum
]]

View File

@ -1,4 +1,233 @@
local quat = require "modules.quat"
local vec3 = require "modules.vec3"
describe("quat:", function()
it("tests creating new quaternions", function()
local a = quat()
assert.is.equal(a.x, 0)
assert.is.equal(a.y, 0)
assert.is.equal(a.z, 0)
assert.is.equal(a.w, 1)
assert.is_true(a:is_quat())
assert.is_true(a:is_real())
local b = quat(0, 0, 0, 0)
assert.is.equal(b.x, 0)
assert.is.equal(b.y, 0)
assert.is.equal(b.z, 0)
assert.is.equal(b.w, 0)
assert.is_true(b:is_zero())
assert.is_true(b:is_imaginary())
local c = quat { 2, 3, 4, 1 }
assert.is.equal(c.x, 2)
assert.is.equal(c.y, 3)
assert.is.equal(c.z, 4)
assert.is.equal(c.w, 1)
local d = quat { x=2, y=3, z=4, w=1 }
assert.is.equal(d.x, 2)
assert.is.equal(d.y, 3)
assert.is.equal(d.z, 4)
assert.is.equal(d.w, 1)
local e = quat.from_angle_axis(math.pi, vec3.unit_z)
local angle, axis = e:to_angle_axis()
assert.is.equal(angle, math.pi)
assert.is.equal(axis, vec3.unit_z)
local f = quat.from_direction(vec3():normalize(vec3(5, 10, 15)), vec3.unit_z)
--assert.is.equal(f.x, 0)
--assert.is.equal(f.y, 0)
--assert.is.equal(f.z, 0)
--assert.is.equal(f.w, 0)
local g = a:clone()
assert.is.equal(g.x, a.x)
assert.is.equal(g.y, a.y)
assert.is.equal(g.z, a.z)
assert.is.equal(g.w, a.w)
end)
it("tests standard operators", function()
local a = quat(2, 3, 4, 1)
local b = quat(3, 6, 9, 1)
do
local c = quat():add(a, b)
assert.is.equal(c.x, 5)
assert.is.equal(c.y, 9)
assert.is.equal(c.z, 13)
assert.is.equal(c.w, 2)
local d = a + b
assert.is.equal(c.x, d.x)
assert.is.equal(c.y, d.y)
assert.is.equal(c.z, d.z)
assert.is.equal(c.w, d.w)
end
do
local c = quat():sub(a, b)
assert.is.equal(c.x, -1)
assert.is.equal(c.y, -3)
assert.is.equal(c.z, -5)
assert.is.equal(c.w, 0)
local d = a - b
assert.is.equal(c.x, d.x)
assert.is.equal(c.y, d.y)
assert.is.equal(c.z, d.z)
assert.is.equal(c.w, d.w)
end
do
local c = quat():mul(a, b)
assert.is.equal(c.x, 8)
assert.is.equal(c.y, 3)
assert.is.equal(c.z, 16)
assert.is.equal(c.w, -59)
local d = a * b
assert.is.equal(c.x, d.x)
assert.is.equal(c.y, d.y)
assert.is.equal(c.z, d.z)
assert.is.equal(c.w, d.w)
end
do
local c = quat():scale(a, 3)
assert.is.equal(c.x, 6)
assert.is.equal(c.y, 9)
assert.is.equal(c.z, 12)
assert.is.equal(c.w, 3)
local d = a * 3
assert.is.equal(c.x, d.x)
assert.is.equal(c.y, d.y)
assert.is.equal(c.z, d.z)
assert.is.equal(c.w, d.w)
local e = -a
assert.is.equal(e.x, -a.x)
assert.is.equal(e.y, -a.y)
assert.is.equal(e.z, -a.z)
assert.is.equal(e.w, -a.w)
end
do
local v = vec3(3, 4, 5)
local c = quat.mul_vec3(vec3(), a, v)
--assert.is.equal(c.x, 0)
--assert.is.equal(c.y, 0)
--assert.is.equal(c.z, 0)
--assert.is.equal(c.w, 0)
local d = a * v
--assert.is.equal(c.x, d.x)
--assert.is.equal(c.y, d.y)
--assert.is.equal(c.z, d.z)
--assert.is.equal(c.w, d.w)
end
do
local c = quat():pow(a, 2)
--assert.is.equal(c.x, 0)
--assert.is.equal(c.y, 0)
--assert.is.equal(c.z, 0)
--assert.is.equal(c.w, 0)
local d = a^2
--assert.is.equal(c.x, d.x)
--assert.is.equal(c.y, d.y)
--assert.is.equal(c.z, d.z)
--assert.is.equal(c.w, d.w)
end
end)
it("tests normal, dot", function()
local a = quat(1, 1, 1, 1)
local b = quat(4, 4, 4, 4)
local c = quat():normalize(a)
local d = a:dot(b)
assert.is.equal(c.x, 0.5)
assert.is.equal(c.y, 0.5)
assert.is.equal(c.z, 0.5)
assert.is.equal(c.w, 0.5)
assert.is.equal(d, 16)
end)
it("tests length", function()
local a = quat(2, 3, 4, 5)
local b = a:len()
local c = a:len2()
assert.is.equal(b, math.sqrt(54))
assert.is.equal(c, 54)
end)
it("tests interpolation", function()
local a = quat(3, 3, 3, 3)
local b = quat(6, 6, 6, 6)
local s = 0.1
local c = quat():lerp(a, b, s)
assert.is.equal(c.x, 0.5)
assert.is.equal(c.y, 0.5)
assert.is.equal(c.z, 0.5)
assert.is.equal(c.w, 0.5)
local d = quat():slerp(a, b, s)
assert.is.equal(d.x, 0.5)
assert.is.equal(d.y, 0.5)
assert.is.equal(d.z, 0.5)
assert.is.equal(d.w, 0.5)
end)
it("tests extraction", function()
local a = quat(2, 3, 4, 1)
local x, y, z, w = a:unpack()
assert.is.equal(x, 2)
assert.is.equal(y, 3)
assert.is.equal(z, 4)
assert.is.equal(w, 1)
local v = a:to_vec3()
assert.is.equal(v.x, 2)
assert.is.equal(v.y, 3)
assert.is.equal(v.z, 4)
end)
it("tests conjugate", function()
local a = quat(2, 3, 4, 1)
local b = quat():conjugate(a)
assert.is.equal(b.x, -2)
assert.is.equal(b.y, -3)
assert.is.equal(b.z, -4)
assert.is.equal(b.w, 1)
end)
it("tests inverse", function()
local a = quat(1, 1, 1, 1)
local b = quat():inverse(a)
assert.is.equal(b.x, -0.5)
assert.is.equal(b.y, -0.5)
assert.is.equal(b.z, -0.5)
assert.is.equal(b.w, 0.5)
end)
it("tests reciprocal", function()
local a = quat(1, 1, 1, 1)
local b = quat():reciprocal(a)
local c = quat():reciprocal(b)
assert.is.equal(c.x, a.x)
assert.is.equal(c.y, a.y)
assert.is.equal(c.z, a.z)
assert.is.equal(c.w, a.w)
end)
end)

View File

@ -3,7 +3,7 @@ local DBL_EPSILON = require("modules.constants").DBL_EPSILON
local abs, sqrt = math.abs, math.sqrt
describe("vec2:", function()
it("Test creating vectors", function()
it("tests creating vectors", function()
-- new empty vector
local a = vec2()
assert.is.equal(a.x, 0)
@ -30,7 +30,7 @@ describe("vec2:", function()
assert.is.equal(d, e)
end)
it("Test basic operators", function()
it("tests basic operators", function()
local a = vec2(3, 5)
local b = vec2(7, 4)
local s = 2
@ -83,7 +83,7 @@ describe("vec2:", function()
end
end)
it("Test normal, trim, length", function()
it("tests normal, trim, length", function()
local a = vec2(3, 5)
local b = vec2():normalize(a)
local c = vec2():trim(a, 0.5)
@ -94,7 +94,7 @@ describe("vec2:", function()
assert.is_true(abs(c:len() - 0.5) < DBL_EPSILON)
end)
it("Test distance", function()
it("tests distance", function()
local a = vec2(3, 5)
local b = vec2(7, 4)
@ -111,7 +111,7 @@ describe("vec2:", function()
end
end)
it("Test cross product", function()
it("tests cross product", function()
local a = vec2(3, 5)
local b = vec2(7, 4)
local c = a:cross(b)
@ -119,7 +119,7 @@ describe("vec2:", function()
assert.is.equal(c, -23)
end)
it("Test dot product", function()
it("tests dot product", function()
local a = vec2(3, 5)
local b = vec2(7, 4)
local c = a:dot(b)
@ -127,7 +127,7 @@ describe("vec2:", function()
assert.is.equal(c, 41)
end)
it("Test lerp", function()
it("tests lerp", function()
local a = vec2(3, 5)
local b = vec2(7, 4)
local s = 0.1
@ -137,7 +137,7 @@ describe("vec2:", function()
assert.is.equal(c.y, 4.9)
end)
it("Test unpack", function()
it("tests unpack", function()
local a = vec2(3, 5)
local x, y = a:unpack()