mirror of
https://github.com/sbrl/Minetest-WorldEditAdditions.git
synced 2024-11-22 15:33:00 +00:00
Vector3: add sort, is_contained, expand_region, mean, min, and max
This commit is contained in:
parent
91b77c981b
commit
65c07d59ea
7 changed files with 367 additions and 0 deletions
48
.tests/Vector3/expand_region.test.lua
Normal file
48
.tests/Vector3/expand_region.test.lua
Normal 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)
|
44
.tests/Vector3/is_contained.test.lua
Normal file
44
.tests/Vector3/is_contained.test.lua
Normal 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)
|
44
.tests/Vector3/max.test.lua
Normal file
44
.tests/Vector3/max.test.lua
Normal 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)
|
47
.tests/Vector3/mean.test.lua
Normal file
47
.tests/Vector3/mean.test.lua
Normal 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)
|
44
.tests/Vector3/min.test.lua
Normal file
44
.tests/Vector3/min.test.lua
Normal 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)
|
44
.tests/Vector3/sort_pos.test.lua
Normal file
44
.tests/Vector3/sort_pos.test.lua
Normal 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)
|
|
@ -253,6 +253,102 @@ function Vector3.abs(a)
|
||||||
return Vector3.new(math.abs(a.x), math.abs(a.y), math.abs(a.z))
|
return Vector3.new(math.abs(a.x), math.abs(a.y), math.abs(a.z))
|
||||||
end
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- ██████ ██████ ███████ ██████ █████ ████████ ██████ ██████
|
-- ██████ ██████ ███████ ██████ █████ ████████ ██████ ██████
|
||||||
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||||
|
|
Loading…
Reference in a new issue