Vector3: add sort, is_contained, expand_region, mean, min, and max

This commit is contained in:
Starbeamrainbowlabs 2021-06-26 17:48:39 +01:00
parent 91b77c981b
commit 65c07d59ea
Signed by: sbrl
GPG Key ID: 1BE5172E637709C2
7 changed files with 367 additions and 0 deletions

View File

@ -0,0 +1,48 @@
local Vector3 = require("worldeditadditions.utils.vector3")
describe("Vector3.expand_region", function()
it("should work with positive vectors", function()
local a = Vector3.new(16, 64, 16)
local b = Vector3.new(1, 4, 6)
local target = Vector3.new(99, 99, 99)
local result_a, result_b = target:expand_region(a, b)
assert.are.same(Vector3.new(1, 4, 6), result_a)
assert.are.same(Vector3.new(99, 99, 99), result_b)
end)
it("should work with mixed components", function()
local a = Vector3.new(16, 1, 16)
local b = Vector3.new(1, 4, 60)
local target = Vector3.new(-99, -99, -99)
local result_a, result_b = target:expand_region(a, b)
assert.are.same(Vector3.new(-99, -99, -99), result_a)
assert.are.same(Vector3.new(16, 4, 60), result_b)
end)
it("should work with negative vectors", function()
local a = Vector3.new(-9, -16, -25)
local b = Vector3.new(-3, -6, -2)
local target = Vector3.new(-99, -99, -99)
local result_a, result_b = target:expand_region(a, b)
assert.are.same(Vector3.new(-99, -99, -99), result_a)
assert.are.same(Vector3.new(-3, -6, -2), result_b)
end)
it("should return new Vector3 instances", function()
local a = Vector3.new(16, 1, 16)
local b = Vector3.new(1, 4, 60)
local target = Vector3.new(99, 99, 99)
local result_a, result_b = target:expand_region(a, b)
assert.are.same(Vector3.new(1, 1, 16), result_a)
assert.are.same(Vector3.new(99, 99, 99), result_b)
result_a.y = 999
result_b.y = 999
assert.are.same(Vector3.new(16, 1, 16), a)
assert.are.same(Vector3.new(1, 4, 60), b)
assert.are.same(Vector3.new(1, 999, 16), result_a)
assert.are.same(Vector3.new(99, 999, 99), result_b)
end)
end)

View File

@ -0,0 +1,44 @@
local Vector3 = require("worldeditadditions.utils.vector3")
describe("Vector3.is_contained", function()
it("should return true when inside", function()
local a = Vector3.new(3, 4, 5)
local b = Vector3.new(30, 40, 50)
local target = Vector3.new(6, 6, 6)
assert.are.same(
true,
target:is_contained(a, b)
)
end)
it("should return false when outside x", function()
local a = Vector3.new(3, 4, 5)
local b = Vector3.new(30, 40, 50)
local target = Vector3.new(60, 6, 6)
assert.are.same(
false,
target:is_contained(a, b)
)
end)
it("should return false when outside y", function()
local a = Vector3.new(3, 4, 5)
local b = Vector3.new(30, 40, 50)
local target = Vector3.new(6, 60, 6)
assert.are.same(
false,
target:is_contained(a, b)
)
end)
it("should return false when outside z", function()
local a = Vector3.new(3, 4, 5)
local b = Vector3.new(30, 40, 50)
local target = Vector3.new(6, 6, 60)
assert.are.same(
false,
target:is_contained(a, b)
)
end)
end)

View File

@ -0,0 +1,44 @@
local Vector3 = require("worldeditadditions.utils.vector3")
describe("Vector3.max", function()
it("should work with positive vectors", function()
local a = Vector3.new(16, 64, 16)
local b = Vector3.new(1, 4, 6)
assert.are.same(
Vector3.new(16, 64, 16),
Vector3.max(a, b)
)
end)
it("should work with mixed components", function()
local a = Vector3.new(16, 1, 16)
local b = Vector3.new(1, 4, 60)
assert.are.same(
Vector3.new(16, 4, 60),
Vector3.max(a, b)
)
end)
it("should work with negative vectors", function()
local a = Vector3.new(-9, -16, -25)
local b = Vector3.new(-3, -6, -2)
assert.are.same(
Vector3.new(-3, -6, -2),
Vector3.max(a, b)
)
end)
it("should return new Vector3 instances", function()
local a = Vector3.new(16, 1, 16)
local b = Vector3.new(1, 4, 60)
local result = Vector3.max(a, b)
assert.are.same(Vector3.new(16, 4, 60), result)
result.y = 999
assert.are.same(Vector3.new(16, 1, 16), a)
assert.are.same(Vector3.new(1, 4, 60), b)
assert.are.same(Vector3.new(16, 999, 60), result)
end)
end)

View File

@ -0,0 +1,47 @@
local Vector3 = require("worldeditadditions.utils.vector3")
describe("Vector3.mean", function()
it("should work with a positive vector", function()
local a = Vector3.new(2, 2, 2)
local b = Vector3.new(4, 4, 4)
assert.are.same(
Vector3.new(3, 3, 3),
a:mean(b)
)
end)
it("should work with a positive vector the other way around", function()
local a = Vector3.new(2, 2, 2)
local b = Vector3.new(4, 4, 4)
assert.are.same(
Vector3.new(3, 3, 3),
b:mean(a)
)
end)
it("should mean another positive vector", function()
local a = Vector3.new(6, 6, 6)
local b = Vector3.new(10, 10, 10)
assert.are.same(
Vector3.new(8, 8, 8),
a:mean(b)
)
end)
it("should mean a negative vector", function()
local a = Vector3.new(-2, -2, -2)
local b = Vector3.new(0, 0, 0)
assert.are.same(
Vector3.new(-1, -1, -1),
a:mean(b)
)
end)
it("should return a new Vector3 instance", function()
local a = Vector3.new(6, 6, 6)
local b = Vector3.new(10, 10, 10)
assert.are.same(
Vector3.new(8, 8, 8),
a:mean(b)
)
assert.are.same(Vector3.new(6, 6, 6), a)
assert.are.same(Vector3.new(10, 10, 10), b)
end)
end)

View File

@ -0,0 +1,44 @@
local Vector3 = require("worldeditadditions.utils.vector3")
describe("Vector3.min", function()
it("should work with positive vectors", function()
local a = Vector3.new(16, 64, 16)
local b = Vector3.new(1, 4, 6)
assert.are.same(
Vector3.new(1, 4, 6),
Vector3.min(a, b)
)
end)
it("should work with mixed components", function()
local a = Vector3.new(16, 1, 16)
local b = Vector3.new(1, 4, 60)
assert.are.same(
Vector3.new(1, 1, 16),
Vector3.min(a, b)
)
end)
it("should work with negative vectors", function()
local a = Vector3.new(-9, -16, -25)
local b = Vector3.new(-3, -6, -2)
assert.are.same(
Vector3.new(-9, -16, -25),
Vector3.min(a, b)
)
end)
it("should return new Vector3 instances", function()
local a = Vector3.new(16, 1, 16)
local b = Vector3.new(1, 4, 60)
local result = Vector3.min(a, b)
assert.are.same(Vector3.new(1, 1, 16), result)
result.y = 999
assert.are.same(Vector3.new(16, 1, 16), a)
assert.are.same(Vector3.new(1, 4, 60), b)
assert.are.same(Vector3.new(1, 999, 16), result)
end)
end)

View File

@ -0,0 +1,44 @@
local Vector3 = require("worldeditadditions.utils.vector3")
describe("Vector3.sort", function()
it("should work with positive vectors", function()
local a = Vector3.new(16, 64, 16)
local b = Vector3.new(1, 4, 6)
local result_a, result_b = Vector3.sort(a, b)
assert.are.same(Vector3.new(1, 4, 6), result_a)
assert.are.same(Vector3.new(16, 64, 16), result_b)
end)
it("should work with mixed components", function()
local a = Vector3.new(16, 1, 16)
local b = Vector3.new(1, 4, 60)
local result_a, result_b = Vector3.sort(a, b)
assert.are.same(Vector3.new(1, 1, 16), result_a)
assert.are.same(Vector3.new(16, 4, 60), result_b)
end)
it("should work with negative vectors", function()
local a = Vector3.new(-9, -16, -25)
local b = Vector3.new(-3, -6, -2)
local result_a, result_b = Vector3.sort(a, b)
assert.are.same(Vector3.new(-9, -16, -25), result_a)
assert.are.same(Vector3.new(-3, -6, -2), result_b)
end)
it("should return new Vector3 instances", function()
local a = Vector3.new(16, 1, 16)
local b = Vector3.new(1, 4, 60)
local result_a, result_b = Vector3.sort(a, b)
assert.are.same(Vector3.new(1, 1, 16), result_a)
assert.are.same(Vector3.new(16, 4, 60), result_b)
result_a.y = 999
result_b.y = 999
assert.are.same(Vector3.new(16, 1, 16), a)
assert.are.same(Vector3.new(1, 4, 60), b)
assert.are.same(Vector3.new(1, 999, 16), result_a)
assert.are.same(Vector3.new(16, 999, 60), result_b)
end)
end)

View File

@ -253,6 +253,102 @@ function Vector3.abs(a)
return Vector3.new(math.abs(a.x), math.abs(a.y), math.abs(a.z))
end
--- Sorts the components of the given vectors.
-- pos1 will contain the minimum values, and pos2 the maximum values.
-- Returns 2 new vectors.
-- Note that the vectors provided do not *have* to be instances of Vector3.
-- It is only required that they have the keys x, y, and z.
-- Vector3 instances are always returned.
-- This enables convenient ingesting of positions from outside.
-- @param pos1 Vector3 The first vector to operate on.
-- @param pos2 Vector3 The second vector to operate on.
-- @returns Vector3,Vector3 The 2 sorted vectors.
function Vector3.sort(pos1, pos2)
local pos1_new = Vector3.clone(pos1) -- This way we can accept non-Vector3 instances
local pos2_new = Vector3.clone(pos2) -- This way we can accept non-Vector3 instances
if pos1_new.x > pos2_new.x then
pos1_new.x, pos2_new.x = pos2_new.x, pos1_new.x
end
if pos1_new.y > pos2_new.y then
pos1_new.y, pos2_new.y = pos2_new.y, pos1_new.y
end
if pos1_new.z > pos2_new.z then
pos1_new.z, pos2_new.z = pos2_new.z, pos1_new.z
end
return pos1_new, pos2_new
end
--- Determines if this vector is contained within the region defined by the given vectors.
-- @param a Vector3 The target vector to check.
-- @param pos1 Vector3 pos1 of the defined region.
-- @param pos2 Vector3 pos2 of the defined region.
-- @return boolean Whether the given target is contained within the defined worldedit region.
function Vector3.is_contained(target, pos1, pos2)
local pos1, pos2 = Vector3.sort(pos1, pos2)
return pos1.x <= target.x
and pos1.y <= target.y
and pos1.z <= target.z
and pos2.x >= target.x
and pos2.y >= target.y
and pos2.z >= target.z
end
--- Expands the defined region to include the given point.
-- @param target Vector3 The target vector to include.
-- @param pos1 Vector3 pos1 of the defined region.
-- @param pos2 Vector3 pos2 of the defined region.
-- @returns Vector3,Vector3 2 vectors that represent the expand_region.
function Vector3.expand_region(target, pos1, pos2)
local pos1, pos2 = Vector3.sort(pos1, pos2)
if target.x < pos1.x then pos1.x = target.x end
if target.y < pos1.y then pos1.y = target.y end
if target.z < pos1.z then pos1.z = target.z end
if target.x > pos2.x then pos2.x = target.x end
if target.y > pos2.y then pos2.y = target.y end
if target.z > pos2.z then pos2.z = target.z end
return pos1, pos2
end
--- Returns the mean (average) of 2 positions.
-- In other words, returns the centre of 2 points.
-- @param pos1 Vector3 pos1 of the defined region.
-- @param pos2 Vector3 pos2 of the defined region.
-- @param target Vector3 Centre coordinates.
function Vector3.mean(pos1, pos2)
return (pos1 + pos2) / 2
end
--- Returns a vector of the min components of 2 vectors.
-- @param pos1 Vector3 The first vector to operate on.
-- @param pos2 Vector3 The second vector to operate on.
-- @return Vector3 The minimum values from the input vectors
function Vector3.min(pos1, pos2)
return Vector3.new(
math.min(pos1.x, pos2.x),
math.min(pos1.y, pos2.y),
math.min(pos1.z, pos2.z)
)
end
--- Returns a vector of the max values of 2 vectors.
-- @param pos1 Vector3 The first vector to operate on.
-- @param pos2 Vector3 The second vector to operate on.
-- @return Vector3 The maximum values from the input vectors.
function Vector3.max(pos1, pos2)
return Vector3.new(
math.max(pos1.x, pos2.x),
math.max(pos1.y, pos2.y),
math.max(pos1.z, pos2.z)
)
end
-- ██████ ██████ ███████ ██████ █████ ████████ ██████ ██████
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██