-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathRamerDouglasPeucker.lua
109 lines (83 loc) · 2.22 KB
/
RamerDouglasPeucker.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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
-- Implementation of the Ramer–Douglas–Peucker algorithm
-- @readme https://github.com/evaera/RobloxLuaAlgorithms#ramerdouglaspeuckerlua
-- @author evaera
-- @version 1.1
-- @date 2021-02-19
function getSqDist(p1, p2, X, Y)
local dx = p1[X] - p2[X]
local dy = p1[Y] - p2[Y]
return dx * dx + dy * dy
end
function getSqSegDist(p, p1, p2, X, Y)
local x = p1[X]
local y = p1[Y]
local dx = p2[X] - x
local dy = p2[Y] - y
if dx ~= 0 or dy ~= 0 then
local t = ((p[X] - x) * dx + (p[Y] - y) * dy) / (dx * dx + dy * dy)
if t > 1 then
x = p2[X]
y = p2[Y]
elseif t > 0 then
x = x + dx * t
y = y + dy * t
end
end
dx = p[X] - x
dy = p[Y] - y
return dx * dx + dy * dy
end
function simplifyRadialDist(points, sqTolerance, X, Y)
local prevPoint = points[1]
local newPoints = {prevPoint}
local point
for i=2, #points do
point = points[i]
if getSqDist(point, prevPoint, X, Y) > sqTolerance then
table.insert(newPoints, point)
prevPoint = point
end
end
if prevPoint ~= point then
table.insert(newPoints, point)
end
return newPoints
end
function simplifyDPStep(points, first, last, sqTolerance, simplified, X, Y)
local maxSqDist = sqTolerance
local index
for i=first+1, last do
local sqDist = getSqSegDist(points[i], points[first], points[last], X, Y)
if sqDist > maxSqDist then
index = i
maxSqDist = sqDist
end
end
if maxSqDist > sqTolerance then
if index - first > 1 then
simplifyDPStep(points, first, index, sqTolerance, simplified, X, Y)
end
table.insert(simplified, points[index])
if last - index > 1 then
simplifyDPStep(points, index, last, sqTolerance, simplified, X, Y)
end
end
end
function simplifyDouglasPeucker(points, sqTolerance, X, Y)
local last = #points
local simplified={points[1]}
simplifyDPStep(points, 1, last, sqTolerance, simplified, X, Y)
table.insert(simplified, points[last])
return simplified
end
return function (points, tolerance, highestQuality, X, Y)
if #points <= 2 then
return points
end
local sqTolerance = tolerance ~= nil and tolerance^2 or 1
X = X or "x"
Y = Y or "y"
points = highestQuality and points or simplifyRadialDist(points, sqTolerance, X, Y)
points = simplifyDouglasPeucker(points, sqTolerance, X, Y)
return points
end