Manual merge PR#51

This commit is contained in:
mcc 2020-05-03 12:46:30 -04:00
commit 6e1cf4be56
14 changed files with 204 additions and 38 deletions

View File

@ -35,3 +35,26 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# The BSD License (BSD-2-Clause)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,11 @@
-- Functions exported by utils.lua but needed by vec2 or vec3 (which utils.lua requires)
local private = {}
local floor = math.floor
function private.round(value, precision)
if precision then return utils.round(value / precision) * precision end
return value >= 0 and floor(value+0.5) or ceil(value-0.5)
end
return private

View File

@ -168,6 +168,14 @@ function bound2.contains(a, v)
and a.max.x >= v.x and a.max.y >= v.y
end
-- Round all components of all vectors to nearest int (or other precision).
-- @tparam vec3 a bound to round.
-- @tparam precision Digits after the decimal (round number if unspecified)
-- @treturn vec3 Rounded bound
function bound2.round(a, precision)
return bound2.new(a.min:round(precision), a.max.round(precision))
end
--- Return a formatted string.
-- @tparam bound2 a bound to be turned into a string
-- @treturn string formatted
@ -183,7 +191,9 @@ function bound2_mt.__call(_, a, b)
end
if status then
ffi.metatype(new, bound2_mt)
xpcall(function() -- Allow this to silently fail; assume failure means someone messed with package.loaded
ffi.metatype(new, bound2_mt)
end, function() end)
end
return setmetatable({}, bound2_mt)

View File

@ -168,6 +168,14 @@ function bound3.contains(a, v)
and a.max.x >= v.x and a.max.y >= v.y and a.max.z >= v.z
end
-- Round all components of all vectors to nearest int (or other precision).
-- @tparam vec3 a bound to round.
-- @tparam precision Digits after the decimal (round number if unspecified)
-- @treturn vec3 Rounded bound
function bound3.round(a, precision)
return bound3.new(a.min:round(precision), a.max:round(precision))
end
--- Return a formatted string.
-- @tparam bound3 a bound to be turned into a string
-- @treturn string formatted
@ -183,7 +191,9 @@ function bound3_mt.__call(_, a, b)
end
if status then
ffi.metatype(new, bound3_mt)
xpcall(function() -- Allow this to silently fail; assume failure means someone messed with package.loaded
ffi.metatype(new, bound3_mt)
end, function() end)
end
return setmetatable({}, bound3_mt)

View File

@ -542,10 +542,10 @@ function mat4.look_at(out, a, eye, look_at, up)
out[10] = y_axis.z
out[11] = z_axis.z
out[12] = 0
out[13] = 0
out[14] = 0
out[15] = 0
out[16] = 1
out[13] = -out[ 1]*eye.x - out[4+1]*eye.y - out[8+1]*eye.z
out[14] = -out[ 2]*eye.x - out[4+2]*eye.y - out[8+2]*eye.z
out[15] = -out[ 3]*eye.x - out[4+3]*eye.y - out[8+3]*eye.z
out[16] = -out[ 4]*eye.x - out[4+4]*eye.y - out[8+4]*eye.z + 1
return out
end
@ -665,7 +665,7 @@ function mat4.to_string(a)
return str
end
--- Convert a matrix to vec4s.
--- Convert a matrix to row vec4s.
-- @tparam mat4 a Matrix to be converted
-- @treturn table vec4s
function mat4.to_vec4s(a)
@ -677,6 +677,18 @@ function mat4.to_vec4s(a)
}
end
--- Convert a matrix to col vec4s.
-- @tparam mat4 a Matrix to be converted
-- @treturn table vec4s
function mat4.to_vec4s_cols(a)
return {
{ a[1], a[5], a[9], a[13] },
{ a[2], a[6], a[10], a[14] },
{ a[3], a[7], a[11], a[15] },
{ a[4], a[8], a[12], a[16] }
}
end
-- http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
--- Convert a matrix to a quaternion.
-- @tparam mat4 a Matrix to be converted
@ -853,7 +865,9 @@ function mat4_mt.__mul(a, b)
end
if status then
ffi.metatype(new, mat4_mt)
xpcall(function() -- Allow this to silently fail; assume failure means someone messed with package.loaded
ffi.metatype(new, mat4_mt)
end, function() end)
end
return setmetatable({}, mat4_mt)

View File

@ -465,7 +465,9 @@ function quat_mt.__pow(a, n)
end
if status then
ffi.metatype(new, quat_mt)
xpcall(function() -- Allow this to silently fail; assume failure means someone messed with package.loaded
ffi.metatype(new, quat_mt)
end, function() end)
end
return setmetatable({}, quat_mt)

View File

@ -4,6 +4,7 @@
local modules = (...): gsub('%.[^%.]+$', '') .. "."
local vec2 = require(modules .. "vec2")
local vec3 = require(modules .. "vec3")
local private = require(modules .. "_private_utils")
local abs = math.abs
local ceil = math.ceil
local floor = math.floor
@ -103,10 +104,7 @@ end
-- @param value
-- @param precision
-- @return number
function utils.round(value, precision)
if precision then return utils.round(value / precision) * precision end
return value >= 0 and floor(value+0.5) or ceil(value-0.5)
end
utils.round = private.round
--- Wrap `value` around if it exceeds `limit`.
-- @param value

View File

@ -3,6 +3,7 @@
local modules = (...):gsub('%.[^%.]+$', '') .. "."
local vec3 = require(modules .. "vec3")
local private = require(modules .. "_private_utils")
local acos = math.acos
local atan2 = math.atan2
local sqrt = math.sqrt
@ -321,6 +322,14 @@ function vec2.to_polar(a)
return radius, theta
end
-- Round all components to nearest int (or other precision).
-- @tparam vec2 a Vector to round.
-- @tparam precision Digits after the decimal (round numebr if unspecified)
-- @treturn vec2 Rounded vector
function vec2.round(a, precision)
return vec2.new(private.round(a.x, precision), private.round(a.y, precision))
end
--- Return a formatted string.
-- @tparam vec2 a Vector to be turned into a string
-- @treturn string formatted
@ -381,7 +390,9 @@ function vec2_mt.__div(a, b)
end
if status then
ffi.metatype(new, vec2_mt)
xpcall(function() -- Allow this to silently fail; assume failure means someone messed with package.loaded
ffi.metatype(new, vec2_mt)
end, function() end)
end
return setmetatable({}, vec2_mt)

View File

@ -1,6 +1,8 @@
--- A 3 component vector.
-- @module vec3
local modules = (...):gsub('%.[^%.]+$', '') .. "."
local private = require(modules .. "_private_utils")
local sqrt = math.sqrt
local cos = math.cos
local sin = math.sin
@ -254,6 +256,14 @@ function vec3.lerp(a, b, s)
return a + (b - a) * s
end
-- Round all components to nearest int (or other precision).
-- @tparam vec3 a Vector to round.
-- @tparam precision Digits after the decimal (round numebr if unspecified)
-- @treturn vec3 Rounded vector
function vec3.round(a, precision)
return vec3.new(private.round(a.x, precision), private.round(a.y, precision), private.round(a.z, precision))
end
--- Unpack a vector into individual components.
-- @tparam vec3 a Vector to unpack
-- @treturn number x
@ -361,7 +371,9 @@ function vec3_mt.__div(a, b)
end
if status then
ffi.metatype(new, vec3_mt)
xpcall(function() -- Allow this to silently fail; assume failure means someone messed with package.loaded
ffi.metatype(new, vec3_mt)
end, function() end)
end
return setmetatable({}, vec3_mt)

View File

@ -38,7 +38,7 @@ describe("bound2:", function()
it("clones a bound2", function()
local a = bound2(vec2(1,2), vec2(4,5))
local b = a:clone()
a.max = new vec2(9,9)
a.max = vec2.new(9,9)
assert.is.equal(a.min, b.min)
assert.is.not_equal(a.max, b.max)
end)
@ -162,13 +162,22 @@ describe("bound2:", function()
it("tests for points inside bound2", function()
local a = bound2(vec2(1,2), vec2(4,5))
assert.is_true(a:contains(vec2(1,2)))
assert.is_true(a:contains(vec2(4,5)))
assert.is_true(a:contains(vec2(2,3)))
assert.is_not_true(a:contains(vec2(0,3)))
assert.is_not_true(a:contains(vec2(5,3)))
assert.is_not_true(a:contains(vec2(2,1)))
assert.is_not_true(a:contains(vec2(2,6)))
assert.is_not_true(a:contains(vec2(2,3)))
assert.is_not_true(a:contains(vec2(2,3)))
end)
it("rounds a bound2", function()
local a = bound2(vec2(1.1,1.9), vec2(3.9,5.1)):round()
assert.is.equal(1, a.min.x)
assert.is.equal(2, a.min.y)
assert.is.equal(4, a.max.x)
assert.is.equal(5, a.max.y)
end)
it("extends a bound2 with a point", function()

View File

@ -46,7 +46,7 @@ describe("bound3:", function()
it("clones a bound3", function()
local a = bound3(vec3(1,2,3), vec3(4,5,6))
local b = a:clone()
a.max = new vec3(9,9,9)
a.max = vec3.new(9,9,9)
assert.is.equal(a.min, b.min)
assert.is.not_equal(a.max, b.max)
end)
@ -199,6 +199,8 @@ describe("bound3:", function()
it("tests for points inside bound3", function()
local a = bound3(vec3(1,2,3), vec3(4,5,6))
assert.is_true(a:contains(vec3(1,2,3)))
assert.is_true(a:contains(vec3(4,5,6)))
assert.is_true(a:contains(vec3(2,3,4)))
assert.is_not_true(a:contains(vec3(0,3,4)))
assert.is_not_true(a:contains(vec3(5,3,4)))
@ -208,6 +210,17 @@ describe("bound3:", function()
assert.is_not_true(a:contains(vec3(2,3,7)))
end)
it("rounds a bound3", function()
local a = bound3(vec3(1.1,1.9,3), vec3(3.9,5.1,6)):round()
assert.is.equal(1, a.min.x)
assert.is.equal(2, a.min.y)
assert.is.equal(3, a.min.z)
assert.is.equal(4, a.max.x)
assert.is.equal(5, a.max.y)
assert.is.equal(6, a.max.z)
end)
it("extends a bound3 with a point", function()
local min = vec3(1,2,6)
local max = vec3(4,5,9)

View File

@ -322,7 +322,12 @@ describe("mat4:", function()
end)
it("converts a matrix to vec4s", function()
local a = mat4()
local a = mat4 {
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16
}
local v = a:to_vec4s()
assert.is_true(type(v) == "table")
assert.is_true(type(v[1]) == "table")
@ -330,25 +335,60 @@ describe("mat4:", function()
assert.is_true(type(v[3]) == "table")
assert.is_true(type(v[4]) == "table")
assert.is.equal(1, v[1][1])
assert.is.equal(0, v[1][2])
assert.is.equal(0, v[1][3])
assert.is.equal(0, v[1][4])
assert.is.equal(1, v[1][1])
assert.is.equal(2, v[1][2])
assert.is.equal(3, v[1][3])
assert.is.equal(4, v[1][4])
assert.is.equal(0, v[2][1])
assert.is.equal(1, v[2][2])
assert.is.equal(0, v[2][3])
assert.is.equal(0, v[2][4])
assert.is.equal(5, v[2][1])
assert.is.equal(6, v[2][2])
assert.is.equal(7, v[2][3])
assert.is.equal(8, v[2][4])
assert.is.equal(0, v[3][1])
assert.is.equal(0, v[3][2])
assert.is.equal(1, v[3][3])
assert.is.equal(0, v[3][4])
assert.is.equal(9, v[3][1])
assert.is.equal(10, v[3][2])
assert.is.equal(11, v[3][3])
assert.is.equal(12, v[3][4])
assert.is.equal(0, v[4][1])
assert.is.equal(0, v[4][2])
assert.is.equal(0, v[4][3])
assert.is.equal(1, v[4][4])
assert.is.equal(13, v[4][1])
assert.is.equal(14, v[4][2])
assert.is.equal(15, v[4][3])
assert.is.equal(16, v[4][4])
end)
it("converts a matrix to vec4s, column-wise", function()
local a = mat4 {
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16
}
local v = a:to_vec4s_cols()
assert.is_true(type(v) == "table")
assert.is_true(type(v[1]) == "table")
assert.is_true(type(v[2]) == "table")
assert.is_true(type(v[3]) == "table")
assert.is_true(type(v[4]) == "table")
assert.is.equal(1, v[1][1])
assert.is.equal(5, v[1][2])
assert.is.equal(9, v[1][3])
assert.is.equal(13, v[1][4])
assert.is.equal(2, v[2][1])
assert.is.equal(6, v[2][2])
assert.is.equal(10, v[2][3])
assert.is.equal(14, v[2][4])
assert.is.equal(3, v[3][1])
assert.is.equal(7, v[3][2])
assert.is.equal(11, v[3][3])
assert.is.equal(15, v[3][4])
assert.is.equal(4, v[4][1])
assert.is.equal(8, v[4][2])
assert.is.equal(12, v[4][3])
assert.is.equal(16, v[4][4])
end)
it("converts a matrix to a quaternion", function()

View File

@ -172,8 +172,8 @@ describe("vec2:", function()
local a = vec2(3, 5)
local r, t = a:to_polar()
local b = vec2.from_cartesian(r, t)
assert.is.equal(a.x, b.x)
assert.is.equal(a.y, b.y)
assert.is_true(abs(a.x - b.x) <= DBL_EPSILON*2) -- Allow 2X epsilon error because there were 2 operations.
assert.is_true(abs(a.y - b.y) <= DBL_EPSILON*2)
end)
it("gets a perpendicular vector", function()
@ -189,6 +189,12 @@ describe("vec2:", function()
assert.is.equal("(+0.000,+0.000)", b)
end)
it("rounds a 2-vector", function()
local a = vec2(1.1,1.9):round()
assert.is.equal(a.x, 1)
assert.is.equal(a.y, 2)
end)
-- Do this last, to insulate tests from accidental state contamination
it("converts a vec3 to vec2 using the constructor", function()
local vec3 = require "modules.vec3"

View File

@ -202,4 +202,11 @@ describe("vec3:", function()
local b = a:to_string()
assert.is.equal("(+0.000,+0.000,+0.000)", b)
end)
it("rounds a 3-vector", function()
local a = vec3(1.1,1.9,3):round()
assert.is.equal(a.x, 1)
assert.is.equal(a.y, 2)
assert.is.equal(a.z, 3)
end)
end)