303 lines
7.1 KiB
Lua
303 lines
7.1 KiB
Lua
local flib_math = require("__flib__/math")
|
|
|
|
--- Utilities for manipulating positions. All functions support both the shorthand and explicit syntaxes and will
|
|
--- preserve the syntax that was passed in.
|
|
--- ```lua
|
|
--- local flib_position = require("__flib__/position")
|
|
--- ```
|
|
--- @class flib_position
|
|
local flib_position = {}
|
|
|
|
--- FIXME: Sumneko doesn't properly handle generics yet and throws a bunch of bogus warnings.
|
|
--- @diagnostic disable
|
|
|
|
--- Add two positions.
|
|
--- @generic P
|
|
--- @param pos1 P
|
|
--- @param pos2 P
|
|
--- @return P
|
|
function flib_position.add(pos1, pos2)
|
|
local x1 = pos1.x or pos1[1]
|
|
local y1 = pos1.y or pos1[2]
|
|
local x2 = pos2.x or pos2[1]
|
|
local y2 = pos2.y or pos2[2]
|
|
if pos1.x then
|
|
return { x = x1 + x2, y = y1 + y2 }
|
|
else
|
|
return { x1 + x2, y1 + y2 }
|
|
end
|
|
end
|
|
|
|
--- Ceil the given position.
|
|
--- @generic P
|
|
--- @param pos P
|
|
--- @return P
|
|
function flib_position.ceil(pos)
|
|
if pos.x then
|
|
return { x = math.ceil(pos.x), y = math.ceil(pos.y) }
|
|
else
|
|
return { math.ceil(pos[1]), math.ceil(pos[2]) }
|
|
end
|
|
end
|
|
|
|
--- Calculate the distance between two positions.
|
|
--- @generic P
|
|
--- @param pos1 P
|
|
--- @param pos2 P
|
|
--- @return number
|
|
function flib_position.distance(pos1, pos2)
|
|
local x1 = pos1.x or pos1[1]
|
|
local y1 = pos1.y or pos1[2]
|
|
local x2 = pos2.x or pos2[1]
|
|
local y2 = pos2.y or pos2[2]
|
|
return math.sqrt((x1 - x2) ^ 2 + (y1 - y2) ^ 2)
|
|
end
|
|
|
|
--- Calculate the squared distance between two positions.
|
|
--- @generic P
|
|
--- @param pos1 P
|
|
--- @param pos2 P
|
|
--- @return number
|
|
function flib_position.distance_squared(pos1, pos2)
|
|
local x1 = pos1.x or pos1[1]
|
|
local y1 = pos1.y or pos1[2]
|
|
local x2 = pos2.x or pos2[1]
|
|
local y2 = pos2.y or pos2[2]
|
|
return (x1 - x2) ^ 2 + (y1 - y2) ^ 2
|
|
end
|
|
|
|
--- Divide two positions.
|
|
--- @generic P
|
|
--- @param pos1 P
|
|
--- @param pos2 P
|
|
--- @return P
|
|
function flib_position.div(pos1, pos2)
|
|
local x1 = pos1.x or pos1[1]
|
|
local y1 = pos1.y or pos1[2]
|
|
local x2 = pos2.x or pos2[1]
|
|
local y2 = pos2.y or pos2[2]
|
|
if pos1.x then
|
|
return { x = x1 / x2, y = y1 / y2 }
|
|
else
|
|
return { x1 / x2, y1 / y2 }
|
|
end
|
|
end
|
|
|
|
--- Return the position in explicit form.
|
|
--- @generic P
|
|
--- @param pos P
|
|
--- @return P
|
|
function flib_position.ensure_explicit(pos)
|
|
if pos.x then
|
|
return pos
|
|
else
|
|
return { x = pos[1], y = pos[2] }
|
|
end
|
|
end
|
|
|
|
--- Return the position in shorthand form.
|
|
--- @generic P
|
|
--- @param pos P
|
|
--- @return P
|
|
function flib_position.ensure_short(pos)
|
|
if pos.x then
|
|
return { pos.x, pos.y }
|
|
else
|
|
return pos
|
|
end
|
|
end
|
|
|
|
--- Test if two positions are equal.
|
|
--- @generic P
|
|
--- @param pos1 P
|
|
--- @param pos2 P
|
|
--- @return boolean
|
|
function flib_position.eq(pos1, pos2)
|
|
local x1 = pos1.x or pos1[1]
|
|
local y1 = pos1.y or pos1[2]
|
|
local x2 = pos2.x or pos2[1]
|
|
local y2 = pos2.y or pos2[2]
|
|
return x1 == x2 and y1 == y2
|
|
end
|
|
|
|
--- Floor the given position.
|
|
--- @generic P
|
|
--- @param pos P
|
|
--- @return P
|
|
function flib_position.floor(pos)
|
|
if pos.x then
|
|
return { x = math.floor(pos.x), y = math.floor(pos.y) }
|
|
else
|
|
return { math.floor(pos[1]), math.floor(pos[2]) }
|
|
end
|
|
end
|
|
|
|
--- Convert a `ChunkPosition` into a `TilePosition` by multiplying by 32.
|
|
--- @param pos ChunkPosition
|
|
--- @return TilePosition
|
|
function flib_position.from_chunk(pos)
|
|
if pos.x then
|
|
return { x = pos.x * 32, y = pos.y * 32 }
|
|
else
|
|
return { pos[1] * 32, pos[2] * 32 }
|
|
end
|
|
end
|
|
|
|
--- Test if `pos1` is greater than or equal to `pos2`.
|
|
--- @generic P
|
|
--- @param pos1 P
|
|
--- @param pos2 P
|
|
--- @return boolean
|
|
function flib_position.ge(pos1, pos2)
|
|
local x1 = pos1.x or pos1[1]
|
|
local y1 = pos1.y or pos1[2]
|
|
local x2 = pos2.x or pos2[1]
|
|
local y2 = pos2.y or pos2[2]
|
|
return x1 >= x2 and y1 >= y2
|
|
end
|
|
|
|
--- Test if `pos1` is greater than `pos2`.
|
|
--- @generic P
|
|
--- @param pos1 P
|
|
--- @param pos2 P
|
|
--- @return boolean
|
|
function flib_position.gt(pos1, pos2)
|
|
local x1 = pos1.x or pos1[1]
|
|
local y1 = pos1.y or pos1[2]
|
|
local x2 = pos2.x or pos2[1]
|
|
local y2 = pos2.y or pos2[2]
|
|
return x1 > x2 and y1 > y2
|
|
end
|
|
|
|
--- Test if `pos1` is less than or equal to `pos2`.
|
|
--- @generic P
|
|
--- @param pos1 P
|
|
--- @param pos2 P
|
|
--- @return boolean
|
|
function flib_position.le(pos1, pos2)
|
|
local x1 = pos1.x or pos1[1]
|
|
local y1 = pos1.y or pos1[2]
|
|
local x2 = pos2.x or pos2[1]
|
|
local y2 = pos2.y or pos2[2]
|
|
return x1 <= x2 and y1 <= y2
|
|
end
|
|
|
|
--- Linearly interpolate between two positions. For example, an amount of 0.5 will return the midpoint.
|
|
--- @generic P
|
|
--- @param pos1 P
|
|
--- @param pos2 P
|
|
--- @param amount number
|
|
--- @return P
|
|
function flib_position.lerp(pos1, pos2, amount)
|
|
if pos1.x then
|
|
return { x = flib_math.lerp(pos1.x, pos2.x, amount), y = flib_math.lerp(pos1.y, pos2.y, amount) }
|
|
else
|
|
return { flib_math.lerp(pos1[1], pos2[1], amount), flib_math.lerp(pos1[2], pos2[2], amount) }
|
|
end
|
|
end
|
|
|
|
--- Test if `pos1` is less than `pos2`.
|
|
--- @generic P
|
|
--- @param pos1 P
|
|
--- @param pos2 P
|
|
--- @return boolean
|
|
function flib_position.lt(pos1, pos2)
|
|
local x1 = pos1.x or pos1[1]
|
|
local y1 = pos1.y or pos1[2]
|
|
local x2 = pos2.x or pos2[1]
|
|
local y2 = pos2.y or pos2[2]
|
|
return x1 < x2 and y1 < y2
|
|
end
|
|
|
|
--- Take the remainder (modulus) of two positions.
|
|
--- @generic P
|
|
--- @param pos1 P
|
|
--- @param pos2 P
|
|
--- @return P
|
|
function flib_position.mod(pos1, pos2)
|
|
local x1 = pos1.x or pos1[1]
|
|
local y1 = pos1.y or pos1[2]
|
|
local x2 = pos2.x or pos2[1]
|
|
local y2 = pos2.y or pos2[2]
|
|
if pos1.x then
|
|
return { x = x1 % x2, y = y1 % y2 }
|
|
else
|
|
return { x1 % x2, y1 % y2 }
|
|
end
|
|
end
|
|
|
|
--- Multiply two positions.
|
|
--- @generic P
|
|
--- @param pos1 P
|
|
--- @param pos2 P
|
|
--- @return P
|
|
function flib_position.mul(pos1, pos2)
|
|
local x1 = pos1.x or pos1[1]
|
|
local y1 = pos1.y or pos1[2]
|
|
local x2 = pos2.x or pos2[1]
|
|
local y2 = pos2.y or pos2[2]
|
|
if pos1.x then
|
|
return { x = x1 * x2, y = y1 * y2 }
|
|
else
|
|
return { x1 * x2, y1 * y2 }
|
|
end
|
|
end
|
|
|
|
--- Subtract two positions.
|
|
--- @generic P
|
|
--- @param pos1 P
|
|
--- @param pos2 P
|
|
--- @return P
|
|
function flib_position.sub(pos1, pos2)
|
|
local x1 = pos1.x or pos1[1]
|
|
local y1 = pos1.y or pos1[2]
|
|
local x2 = pos2.x or pos2[1]
|
|
local y2 = pos2.y or pos2[2]
|
|
if pos1.x then
|
|
return { x = x1 - x2, y = y1 - y2 }
|
|
else
|
|
return { x1 - x2, y1 - y2 }
|
|
end
|
|
end
|
|
|
|
--- Take the power of two positions. `pos1^pos2`.
|
|
--- @generic P
|
|
--- @param pos1 P
|
|
--- @param pos2 P
|
|
--- @return P
|
|
function flib_position.pow(pos1, pos2)
|
|
local x1 = pos1.x or pos1[1]
|
|
local y1 = pos1.y or pos1[2]
|
|
local x2 = pos2.x or pos2[1]
|
|
local y2 = pos2.y or pos2[2]
|
|
if pos1.x then
|
|
return { x = x1 ^ x2, y = y1 ^ y2 }
|
|
else
|
|
return { x1 ^ x2, y1 ^ y2 }
|
|
end
|
|
end
|
|
|
|
--- Convert a `MapPosition` or `TilePosition` into a `ChunkPosition` by dividing by 32 and flooring.
|
|
--- @param pos MapPosition|TilePosition
|
|
--- @return ChunkPosition
|
|
function flib_position.to_chunk(pos)
|
|
if pos.x then
|
|
return { x = math.floor(pos.x / 32), y = math.floor(pos.y / 32) }
|
|
else
|
|
return { math.floor(pos[1] / 32), math.floor(pos[2] / 32) }
|
|
end
|
|
end
|
|
|
|
--- Convert a `MapPosition` into a `TilePosition` by flooring.
|
|
--- @param pos MapPosition
|
|
--- @return TilePosition
|
|
function flib_position.to_tile(pos)
|
|
if pos.x then
|
|
return { x = math.floor(pos.x), y = math.floor(pos.y) }
|
|
else
|
|
return { math.floor(pos[1]), math.floor(pos[2]) }
|
|
end
|
|
end
|
|
|
|
return flib_position
|