-
Notifications
You must be signed in to change notification settings - Fork 7
/
grahamscan.lua
47 lines (38 loc) · 1.31 KB
/
grahamscan.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
local function orientation(p, q, r)
local val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y)
if val == 0 then return 0 end
return val > 0 and 1 or 2
end
local function grahamScan(points)
if #points < 3 then return points end
-- Find the bottommost point (and leftmost if there are multiple)
local bottom = 1
for i = 2, #points do
if points[i].y < points[bottom].y or (points[i].y == points[bottom].y and points[i].x < points[bottom].x) then
bottom = i
end
end
-- Swap the bottommost point with the first point
points[1], points[bottom] = points[bottom], points[1]
-- Sort points based on polar angle with respect to the bottommost point
local p0 = points[1]
table.sort(points, function(a, b)
local o = orientation(p0, a, b)
if o == 0 then
return (a.x - p0.x)^2 + (a.y - p0.y)^2 < (b.x - p0.x)^2 + (b.y - p0.y)^2
end
return o == 2
end)
-- Build the convex hull
local stack = {points[1], points[2], points[3]}
for i = 4, #points do
while #stack > 1 and orientation(stack[#stack-1], stack[#stack], points[i]) ~= 2 do
table.remove(stack)
end
table.insert(stack, points[i])
end
return stack
end
return {
approximate_circle = grahamScan
}