134 lines
3.8 KiB
Lua
134 lines
3.8 KiB
Lua
---@class RamerDouglasPeucker
|
||
local RamerDouglasPeucker = QuestieLoader:CreateModule("RamerDouglasPeucker")
|
||
|
||
|
||
-- code after this point is Ramer-Douglas-Peucker algorithm implemented by Eryn Lynn
|
||
--[[
|
||
MIT License
|
||
|
||
Copyright (c) 2018 Eryn Lynn
|
||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
of this software and associated documentation files (the "Software"), to deal
|
||
in the Software without restriction, including without limitation the rights
|
||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
copies of the Software, and to permit persons to whom the Software is
|
||
furnished to do so, subject to the following conditions:
|
||
|
||
The above copyright notice and this permission notice shall be included in all
|
||
copies or substantial portions of the Software.
|
||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||
SOFTWARE. ]]
|
||
-- Implementation of the Ramer–Douglas–Peucker algorithm
|
||
-- readme https://github.com/evaera/RobloxLuaAlgorithms#ramerdouglaspeuckerlua
|
||
-- author: evaera
|
||
|
||
|
||
local function getSqDist(p1, p2)
|
||
local dx = p1[1] - p2[1]
|
||
local dy = p1[2] - p2[2]
|
||
|
||
return dx * dx + dy * dy
|
||
end
|
||
|
||
local function simplifyRadialDist(points, sqTolerance)
|
||
local prevPoint = points[1]
|
||
local newPoints = {prevPoint}
|
||
local point
|
||
|
||
for i=2, #points do
|
||
point = points[i]
|
||
|
||
if getSqDist(point, prevPoint) > sqTolerance then
|
||
table.insert(newPoints, point)
|
||
prevPoint = point
|
||
end
|
||
end
|
||
|
||
if prevPoint ~= point then
|
||
table.insert(newPoints, point)
|
||
end
|
||
|
||
return newPoints
|
||
end
|
||
|
||
local function getSqSegDist(p, p1, p2)
|
||
local x = p1[1]
|
||
local y = p1[2]
|
||
local dx = p2[1] - x
|
||
local dy = p2[2] - y
|
||
|
||
if dx ~= 0 or dy ~= 0 then
|
||
local t = ((p[1] - x) * dx + (p[2] - y) * dy) / (dx * dx + dy * dy)
|
||
|
||
if t > 1 then
|
||
x = p2[1]
|
||
y = p2[2]
|
||
elseif t > 0 then
|
||
x = x + dx * t
|
||
y = y + dy * t
|
||
end
|
||
end
|
||
|
||
dx = p[1] - x
|
||
dy = p[2] - y
|
||
|
||
return dx * dx + dy * dy
|
||
end
|
||
|
||
local function simplifyDPStep(points, first, last, sqTolerance, simplified)
|
||
local maxSqDist = sqTolerance
|
||
local index
|
||
|
||
for i=first+1, last do
|
||
local sqDist = getSqSegDist(points[i], points[first], points[last])
|
||
|
||
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)
|
||
end
|
||
|
||
table.insert(simplified, points[index])
|
||
|
||
if last - index > 1 then
|
||
simplifyDPStep(points, index, last, sqTolerance, simplified)
|
||
end
|
||
end
|
||
end
|
||
|
||
local function simplifyDouglasPeucker(points, sqTolerance)
|
||
local last = #points
|
||
|
||
local simplified={points[1]}
|
||
simplifyDPStep(points, 1, last, sqTolerance, simplified)
|
||
table.insert(simplified, points[last])
|
||
|
||
return simplified
|
||
end
|
||
|
||
local _RamerDouglasPeucker = function(points, tolerance, highestQuality)
|
||
if #points <= 2 then
|
||
return points
|
||
end
|
||
|
||
local sqTolerance = tolerance ~= nil and tolerance^2 or 1
|
||
|
||
points = highestQuality and points or simplifyRadialDist(points, sqTolerance)
|
||
points = simplifyDouglasPeucker(points, sqTolerance)
|
||
|
||
return points
|
||
end
|
||
|
||
setmetatable(RamerDouglasPeucker, { __call = function(_, ...) return _RamerDouglasPeucker(...) end}) |