Skip to content

Commit 4a38b42

Browse files
committed
library implementation, version 1
1 parent 425be9d commit 4a38b42

File tree

2 files changed

+199
-0
lines changed

2 files changed

+199
-0
lines changed

init.lua

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
local min, max = math.min, math.max
2+
3+
---The rectangle class that implements the algorithm.
4+
---Can be called to instantiate a Rect.
5+
---@class Rect
6+
---@field public minX number
7+
---@field public minY number
8+
---@field public maxX number
9+
---@field public maxY number
10+
---@overload fun(minX: number, minY: number, maxX: number, maxY: number): Rect
11+
---@overload fun(r: {minX: number, minY: number, maxX: number, maxY: number}): Rect
12+
local Rect = {}
13+
Rect.__index = Rect
14+
15+
---Creates a new Rect. Equivalent to calling the class: `Rect(...)`.
16+
---@param minX number
17+
---@param minY number
18+
---@param maxX number
19+
---@param maxY number
20+
---@return Rect
21+
---@overload fun(r: {minX: number, minY: number, maxX: number, maxY: number}): Rect
22+
function Rect.new(minX, minY, maxX, maxY)
23+
if type(minX) == "table" then
24+
minX, minY, maxX, maxY = minX.minX, minX.minY, minX.maxX, minY.maxY
25+
end
26+
27+
return setmetatable({
28+
minX = minX,
29+
minY = minY,
30+
maxX = maxX,
31+
maxY = maxY,
32+
}, Rect)
33+
end
34+
35+
---Creates a new Rect from XYWH parameters.
36+
---@param x number
37+
---@param y number
38+
---@param width number
39+
---@param height number
40+
---@return Rect
41+
---@overload fun(r: {x: number, y: number, width: number, height: number}): Rect
42+
function Rect.fromXYWH(x, y, width, height)
43+
if type(x) == "table" then
44+
x, y, width, height = x.x, x.y, x.width, x.height
45+
end
46+
47+
return setmetatable({
48+
minX = x,
49+
minY = y,
50+
maxX = x + width,
51+
maxY = y + height,
52+
}, Rect)
53+
end
54+
55+
---Returns all components of this Rect.
56+
---@return number minX, number minY, number maxX, number maxY
57+
function Rect:unpack() return self.minX, self.minY, self.maxX, self.maxY end
58+
59+
---Returns the components of this Rect, in XYWH format.
60+
---@return number x, number y, number width, number height
61+
function Rect:xywh()
62+
return self.minX, self.minY,
63+
self.minX + (self.maxX - self.minX),
64+
self.minY + (self.maxY - self.minY)
65+
end
66+
67+
---Same as `cut_left`, except it keeps the Rect intact.
68+
---@param a number
69+
---@return Rect
70+
function Rect:get_left(a)
71+
return Rect.new(
72+
self.minX, self.minY,
73+
min(self.maxX, self.minX + a), self.maxY
74+
)
75+
end
76+
77+
---Same as `cut_right`, expect it keeps the Rect intact.
78+
---@param a number
79+
---@return Rect
80+
function Rect:get_right(a)
81+
return Rect.new(
82+
max(self.minX, self.maxX - a), self.minY,
83+
self.maxX, self.maxY
84+
)
85+
end
86+
87+
---Same as `cut_top`, expect it keeps the Rect intact.
88+
---@param a number
89+
---@return Rect
90+
function Rect:get_top(a)
91+
return Rect.new(
92+
self.minX, self.minY,
93+
self.maxX, min(self.maxY, self.minY + a)
94+
)
95+
end
96+
97+
---Same as `cut_bottom`, expect it keeps the Rect intact.
98+
---@param a number
99+
---@return Rect
100+
function Rect:get_bottom(a)
101+
return Rect.new(
102+
self.minX, max(self.minY, self.maxY - a),
103+
self.maxX, self.maxY
104+
)
105+
end
106+
107+
---Cuts `a` from the left side of the Rect, and returns the cut part.
108+
---@param a number
109+
---@return Rect
110+
function Rect:cut_left(a)
111+
local left = self:get_left(a)
112+
self.minX = left.minX
113+
return left
114+
end
115+
116+
---Cuts `a` from the right side of the Rect, and returns the cut part.
117+
---@param a number
118+
---@return Rect
119+
function Rect:cut_right(a)
120+
local right = self:get_right(a)
121+
self.maxX = right.maxX
122+
return right
123+
end
124+
125+
---Cuts `a` from the top side of the Rect, and returns the cut part.
126+
---@param a number
127+
---@return Rect
128+
function Rect:cut_top(a)
129+
local top = self:get_top(a)
130+
self.minY = top.minY
131+
return top
132+
end
133+
134+
---Cuts `a` from the bottom side of the Rect, and returns the cut part.
135+
---@param a number
136+
---@return Rect
137+
function Rect:cut_bottom(a)
138+
local bottom = self:get_bottom(a)
139+
self.maxY = bottom.maxY
140+
return bottom
141+
end
142+
143+
---Returns this rect, with `a` added to its left side.
144+
---@param a number
145+
---@return Rect
146+
function Rect:add_left(a) return Rect.new(self.minX - a, self.minY, self.maxX, self.maxY) end
147+
148+
---Returns this rect, with `a` added to its right side.
149+
---@param a number
150+
---@return Rect
151+
function Rect:add_right(a) return Rect.new(self.minX, self.minY, self.maxX + a, self.maxY) end
152+
153+
---Returns this rect, with `a` added to its top side.
154+
---@param a number
155+
---@return Rect
156+
function Rect:add_top(a) return Rect.new(self.minX, self.minY - a, self.maxX, self.maxY) end
157+
158+
---Returns this rect, with `a` added to its bottom side.
159+
---@param a number
160+
---@return Rect
161+
function Rect:add_bottom(a) return Rect.new(self.minX, self.minY, self.maxX, self.maxY + a) end
162+
163+
---Returns an extended version of this Rect.
164+
---@param a number
165+
---@return Rect
166+
function Rect:extend(a) return Rect.new(self.minX - a, self.minY - a, self.maxX + a, self.maxY + a) end
167+
168+
---Returns a contracted version of this Rect.
169+
---@param a number
170+
---@return Rect
171+
function Rect:contract(a) return Rect.new(self.minX + a, self.minY + a, self.maxX - a, self.maxY - a) end
172+
173+
---@return string
174+
function Rect:__tostring()
175+
return string.format("Rect: X(%f-%f), Y(%f-%f)", self:unpack())
176+
end
177+
178+
return setmetatable(Rect, {
179+
__call = function(cls, ...) return cls.new(...) end,
180+
})

tests.lua

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
local Rect = require 'init'
2+
3+
local fail = false
4+
5+
local function testEqualRects(name, a, b)
6+
if a.minX ~= b.minX or a.minY ~= b.minY
7+
or a.maxX ~= b.maxX or a.maxY ~= b.maxY then
8+
io.write(name .. " failed: expected " .. tostring(b) .. ", got " .. tostring(a) .. "\n")
9+
fail = true
10+
return false
11+
else
12+
io.write(name .. " passed\n")
13+
return true
14+
end
15+
end
16+
17+
-- TODO: actually write tests lmfao
18+
19+
if fail then io.write("\nsome tests have failed, please check results\n") end

0 commit comments

Comments
 (0)