Small update
I tried to take inspiration from this gist on GitHub:
https://gist.github.com/dwyerk/10561690
And using this Lua adaptation of the Delaunay triangulation to replace the Python module
scipy.spatial.Delaunay:
https://github.com/Yonaba/delaunay
I also reused the script from my first post if the number of points given is less than 4.
Here's where I'm at so far, but it's not working:
Code: Select all
local path = ...
local alphaShape = {}
alphaShape.delaunay = require(path.."/delaunay")
alphaShape.getConvexHull = require(path.."/convexHull")
local Point = alphaShape.delaunay.Point
local addEdge = function(edge_points, points, edges, i, j)
-- Add a line between the i-th and j-th points, if not in the list already
for _, v in pairs(edges) do
if v[1] == i and v[2] == j
or v[1] == j and v[2] == i
then return end -- already added
end
table.insert(edge_points, points[i])
table.insert(edge_points, points[j])
table.insert(edges, {i, j})
end
alphaShape.getConcaveHull = function(points, alpha)
--[[
Compute the alpha shape (concave hull) of a set of points.
@param points: Iterable container of points.
@param alpha: alpha value to influence the gooeyness of the border. Smaller
numbers don't fall inward as much as larger numbers. Too large,
and you lose everything!
]]
if #points < 4 then -- When you have a triangle, there is no sense in computing an alpha shape.
return alphaShape.getConvexHull(points)
end
local coords = {}
for _, point in pairs(points) do
table.insert(coords, Point(point[1], point[2]))
end
local triangles = alphaShape.delaunay.triangulate(unpack(coords))
local edge_points, edges = {}, {}
-- Loop over triangles: ia, ib, ic = indices of corner points of the triangle
for _, tri in pairs(triangles) do
local ia = tri.p1.id
local ib = tri.p2.id
local ic = tri.p3.id
local pa = points[ia] -- or : {tri.p1.x, tri.p1.y}
local pb = points[ib]
local pc = points[ic]
-- Computing radius of triangle circumcircle
local a = math.sqrt((pa[1] - pb[1]) ^ 2 + (pa[2] - pb[2]) ^ 2)
local b = math.sqrt((pb[1] - pc[1]) ^ 2 + (pb[2] - pc[2]) ^ 2)
local c = math.sqrt((pc[1] - pa[1]) ^ 2 + (pc[2] - pa[2]) ^ 2)
local s = (a + b + c) / 2.0
local area = math.sqrt(s * (s - a) * (s - b) * (s - c))
local circum_r = a * b * c / (4.0 * area)
if circum_r < alpha then
addEdge(edge_points, points, edges, ia, ib)
addEdge(edge_points, points, edges, ib, ic)
addEdge(edge_points, points, edges, ic, ia)
end
end
return edge_points, edges
end
return alphaShape
The problem is that the condition 'if circum_r < alpha then' is never true because 'circum_r' is always greater than +/- 100x the 'alpha' value (which equals 0.4 in my tests).
I'm still working on it, if anyone has any suggestions I'm all ears !