mirror of
https://github.com/luanti-org/luanti.git
synced 2025-08-01 17:38:41 +00:00
Add new vector utils (ceil, sign, abs, random_in_area) (#14807)
This commit is contained in:
parent
3971b6afcc
commit
a6ba5304c4
10 changed files with 143 additions and 52 deletions
41
builtin/common/math.lua
Normal file
41
builtin/common/math.lua
Normal file
|
@ -0,0 +1,41 @@
|
|||
--[[
|
||||
Math utils.
|
||||
--]]
|
||||
|
||||
function math.hypot(x, y)
|
||||
return math.sqrt(x * x + y * y)
|
||||
end
|
||||
|
||||
function math.sign(x, tolerance)
|
||||
tolerance = tolerance or 0
|
||||
if x > tolerance then
|
||||
return 1
|
||||
elseif x < -tolerance then
|
||||
return -1
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
function math.factorial(x)
|
||||
assert(x % 1 == 0 and x >= 0, "factorial expects a non-negative integer")
|
||||
if x >= 171 then
|
||||
-- 171! is greater than the biggest double, no need to calculate
|
||||
return math.huge
|
||||
end
|
||||
local v = 1
|
||||
for k = 2, x do
|
||||
v = v * k
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
function math.round(x)
|
||||
if x < 0 then
|
||||
local int = math.ceil(x)
|
||||
local frac = x - int
|
||||
return int - ((frac <= -0.5) and 1 or 0)
|
||||
end
|
||||
local int = math.floor(x)
|
||||
local frac = x - int
|
||||
return int + ((frac >= 0.5) and 1 or 0)
|
||||
end
|
|
@ -3,6 +3,7 @@
|
|||
--------------------------------------------------------------------------------
|
||||
-- Localize functions to avoid table lookups (better performance).
|
||||
local string_sub, string_find = string.sub, string.find
|
||||
local math = math
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
local function basic_dump(o)
|
||||
|
@ -220,47 +221,6 @@ function string:trim()
|
|||
return self:match("^%s*(.-)%s*$")
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function math.hypot(x, y)
|
||||
return math.sqrt(x * x + y * y)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function math.sign(x, tolerance)
|
||||
tolerance = tolerance or 0
|
||||
if x > tolerance then
|
||||
return 1
|
||||
elseif x < -tolerance then
|
||||
return -1
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function math.factorial(x)
|
||||
assert(x % 1 == 0 and x >= 0, "factorial expects a non-negative integer")
|
||||
if x >= 171 then
|
||||
-- 171! is greater than the biggest double, no need to calculate
|
||||
return math.huge
|
||||
end
|
||||
local v = 1
|
||||
for k = 2, x do
|
||||
v = v * k
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
function math.round(x)
|
||||
if x < 0 then
|
||||
local int = math.ceil(x)
|
||||
local frac = x - int
|
||||
return int - ((frac <= -0.5) and 1 or 0)
|
||||
end
|
||||
local int = math.floor(x)
|
||||
local frac = x - int
|
||||
return int + ((frac >= 0.5) and 1 or 0)
|
||||
end
|
||||
|
||||
local formspec_escapes = {
|
||||
["\\"] = "\\\\",
|
||||
["["] = "\\[",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
_G.core = {}
|
||||
_G.vector = {metatable = {}}
|
||||
|
||||
dofile("builtin/common/math.lua")
|
||||
dofile("builtin/common/vector.lua")
|
||||
dofile("builtin/common/misc_helpers.lua")
|
||||
|
||||
|
|
16
builtin/common/tests/math_spec.lua
Normal file
16
builtin/common/tests/math_spec.lua
Normal file
|
@ -0,0 +1,16 @@
|
|||
_G.core = {}
|
||||
dofile("builtin/common/math.lua")
|
||||
|
||||
describe("math", function()
|
||||
it("round()", function()
|
||||
assert.equal(0, math.round(0))
|
||||
assert.equal(10, math.round(10.3))
|
||||
assert.equal(11, math.round(10.5))
|
||||
assert.equal(11, math.round(10.7))
|
||||
assert.equal(-10, math.round(-10.3))
|
||||
assert.equal(-11, math.round(-10.5))
|
||||
assert.equal(-11, math.round(-10.7))
|
||||
assert.equal(0, math.round(0.49999999999999994))
|
||||
assert.equal(0, math.round(-0.49999999999999994))
|
||||
end)
|
||||
end)
|
|
@ -1,4 +1,5 @@
|
|||
_G.core = {}
|
||||
dofile("builtin/common/math.lua")
|
||||
dofile("builtin/common/vector.lua")
|
||||
dofile("builtin/common/misc_helpers.lua")
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
_G.vector = {}
|
||||
dofile("builtin/common/math.lua")
|
||||
dofile("builtin/common/vector.lua")
|
||||
|
||||
describe("vector", function()
|
||||
|
@ -113,12 +114,35 @@ describe("vector", function()
|
|||
assert.equal(vector.new(0, 1, -1), a:round())
|
||||
end)
|
||||
|
||||
it("ceil()", function()
|
||||
local a = vector.new(0.1, 0.9, -0.5)
|
||||
assert.equal(vector.new(1, 1, 0), vector.ceil(a))
|
||||
assert.equal(vector.new(1, 1, 0), a:ceil())
|
||||
end)
|
||||
|
||||
it("sign()", function()
|
||||
local a = vector.new(-120.3, 0, 231.5)
|
||||
assert.equal(vector.new(-1, 0, 1), vector.sign(a))
|
||||
assert.equal(vector.new(-1, 0, 1), a:sign())
|
||||
assert.equal(vector.new(0, 0, 1), vector.sign(a, 200))
|
||||
assert.equal(vector.new(0, 0, 1), a:sign(200))
|
||||
end)
|
||||
|
||||
it("abs()", function()
|
||||
local a = vector.new(-123.456, 0, 13)
|
||||
assert.equal(vector.new(123.456, 0, 13), vector.abs(a))
|
||||
assert.equal(vector.new(123.456, 0, 13), a:abs())
|
||||
end)
|
||||
|
||||
it("apply()", function()
|
||||
local i = 0
|
||||
local f = function(x)
|
||||
i = i + 1
|
||||
return x + i
|
||||
end
|
||||
local f2 = function(x, opt1, opt2, opt3)
|
||||
return x + opt1 + opt2 + opt3
|
||||
end
|
||||
local a = vector.new(0.1, 0.9, -0.5)
|
||||
assert.equal(vector.new(1, 1, 0), vector.apply(a, math.ceil))
|
||||
assert.equal(vector.new(1, 1, 0), a:apply(math.ceil))
|
||||
|
@ -126,6 +150,9 @@ describe("vector", function()
|
|||
assert.equal(vector.new(0.1, 0.9, 0.5), a:apply(math.abs))
|
||||
assert.equal(vector.new(1.1, 2.9, 2.5), vector.apply(a, f))
|
||||
assert.equal(vector.new(4.1, 5.9, 5.5), a:apply(f))
|
||||
local b = vector.new(1, 2, 3)
|
||||
assert.equal(vector.new(4, 5, 6), vector.apply(b, f2, 1, 1, 1))
|
||||
assert.equal(vector.new(4, 5, 6), b:apply(f2, 1, 1, 1))
|
||||
end)
|
||||
|
||||
it("combine()", function()
|
||||
|
@ -469,4 +496,13 @@ describe("vector", function()
|
|||
assert.True(vector.in_area(vector.new(-10, -10, -10), vector.new(-10, -10, -10), vector.new(10, 10, 10)))
|
||||
assert.False(vector.in_area(vector.new(-10, -10, -10), vector.new(10, 10, 10), vector.new(-11, -10, -10)))
|
||||
end)
|
||||
|
||||
it("random_in_area()", function()
|
||||
local min = vector.new(-100, -100, -100)
|
||||
local max = vector.new(100, 100, 100)
|
||||
for i = 1, 1000 do
|
||||
local random = vector.random_in_area(min, max)
|
||||
assert.True(vector.in_area(random, min, max))
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
|
|
@ -5,6 +5,7 @@ Note: The vector.*-functions must be able to accept old vectors that had no meta
|
|||
|
||||
-- localize functions
|
||||
local setmetatable = setmetatable
|
||||
local math = math
|
||||
|
||||
vector = {}
|
||||
|
||||
|
@ -97,18 +98,26 @@ function vector.floor(v)
|
|||
end
|
||||
|
||||
function vector.round(v)
|
||||
return fast_new(
|
||||
math.round(v.x),
|
||||
math.round(v.y),
|
||||
math.round(v.z)
|
||||
)
|
||||
return vector.apply(v, math.round)
|
||||
end
|
||||
|
||||
function vector.apply(v, func)
|
||||
function vector.ceil(v)
|
||||
return vector.apply(v, math.ceil)
|
||||
end
|
||||
|
||||
function vector.sign(v, tolerance)
|
||||
return vector.apply(v, math.sign, tolerance)
|
||||
end
|
||||
|
||||
function vector.abs(v)
|
||||
return vector.apply(v, math.abs)
|
||||
end
|
||||
|
||||
function vector.apply(v, func, ...)
|
||||
return fast_new(
|
||||
func(v.x),
|
||||
func(v.y),
|
||||
func(v.z)
|
||||
func(v.x, ...),
|
||||
func(v.y, ...),
|
||||
func(v.z, ...)
|
||||
)
|
||||
end
|
||||
|
||||
|
@ -387,6 +396,14 @@ function vector.random_direction()
|
|||
return fast_new(x/l, y/l, z/l)
|
||||
end
|
||||
|
||||
function vector.random_in_area(min, max)
|
||||
return fast_new(
|
||||
math.random(min.x, max.x),
|
||||
math.random(min.y, max.y),
|
||||
math.random(min.z, max.z)
|
||||
)
|
||||
end
|
||||
|
||||
if rawget(_G, "core") and core.set_read_vector and core.set_push_vector then
|
||||
local function read_vector(v)
|
||||
return v.x, v.y, v.z
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue