Skip to content

Commit

Permalink
Create functions for detecting each shape
Browse files Browse the repository at this point in the history
  • Loading branch information
David Minnerly committed Apr 30, 2021
1 parent 8ccc4c4 commit 122de2c
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 48 deletions.
56 changes: 8 additions & 48 deletions src/detectShape.lua
Original file line number Diff line number Diff line change
@@ -1,26 +1,14 @@
local sortCounterClockwise = require(script.Parent.sortCounterClockwise)
local getConvexHull = require(script.Parent.getConvexHull)
local getPerimeter = require(script.Parent.getPerimeter)
local getPolygonArea = require(script.Parent.getPolygonArea)
local getBoundingBox = require(script.Parent.getBoundingBox)
local getLargestTriangle = require(script.Parent.getLargestTriangle)
local getSideLengths = require(script.Parent.getSideLengths)
local getTriangleArea = require(script.Parent.getTriangleArea)
local isLine = require(script.Parent.isLine)
local isChevron = require(script.Parent.isChevron)
local isCircle = require(script.Parent.isCircle)
local isRectangle = require(script.Parent.isRectangle)
local isSquare = require(script.Parent.isSquare)
local isTriangle = require(script.Parent.isTriangle)
local Shape = require(script.Parent.Shape)

local LINE_THRESHHOLD = 30
local SQUARE_PERCENT = 0.60
local RECTANGLE_PERCENT = 0.75
local TRIANGLE_PERCENT = 0.75

local CIRCLE = 4 * math.pi

local function fuzzyeq(a, b, epsilon)
return math.abs(a - b) <= epsilon
end

local function detectShape(points: {[number]: Vector2})
if isLine(points) then
return Shape.Line
Expand All @@ -30,43 +18,15 @@ local function detectShape(points: {[number]: Vector2})

local sorted = sortCounterClockwise(points)
local hull = getConvexHull(sorted)

local hullArea = getPolygonArea(hull)
local perimeter = getPerimeter(hull)

local rectangle = getBoundingBox(hull)
local sides = getSideLengths(rectangle)
local rectangleArea = sides.X * sides.Y
local maxSide = math.max(sides.X, sides.Y)

local triangle = getLargestTriangle(hull)
local triangleArea = getTriangleArea(unpack(triangle))

-- Goes to infinity for lines and approaches 4pi for circles.
local thinnessRatio = perimeter^2 / hullArea
-- Approaches unity
local squareRatio = hullArea / maxSide^2
-- Approaches unity
local rectangleRatio = hullArea / rectangleArea
-- Approaches unity
local triangleRatio = triangleArea / hullArea

-- print("thinnessRatio", thinnessRatio)
-- print("squareRatio", squareRatio)
-- print("rectangleRatio", rectangleRatio)
-- print("triangleRatio", triangleRatio)

-- Triangles tend to have a thinnessRatio that approaches 4pi, so we also
-- compare with the triangleRatio to ensure we detect the correct shape/
if fuzzyeq(CIRCLE, thinnessRatio, 1) and triangleRatio < TRIANGLE_PERCENT then
if isCircle(hull, hullArea) then
return Shape.Circle
elseif squareRatio >= SQUARE_PERCENT then
elseif isSquare(hull, hullArea) then
return Shape.Square
elseif rectangleRatio >= RECTANGLE_PERCENT then
elseif isRectangle(hull, hullArea) then
return Shape.Rectangle
elseif thinnessRatio >= LINE_THRESHHOLD then
return Shape.Line
elseif triangleRatio >= TRIANGLE_PERCENT then
elseif isTriangle(hull, hullArea) then
return Shape.Triangle
end
end
Expand Down
17 changes: 17 additions & 0 deletions src/isCircle.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
local getPerimeter = require(script.Parent.getPerimeter)

local function fuzzyeq(a, b, epsilon)
return math.abs(a - b) <= epsilon
end

local function isCircle(hull: { Vector2 }, hullArea: number)
local perimeter = getPerimeter(hull)

-- This ratio approaches 4pi for circles, so we will then compare that the
-- ratio is roughly close to that value for circle detection.
local thinnessRatio = perimeter^2 / hullArea

return fuzzyeq(4 * math.pi, thinnessRatio, 1)
end

return isCircle
14 changes: 14 additions & 0 deletions src/isRectangle.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
local getBoundingBox = require(script.Parent.getBoundingBox)
local getSideLengths = require(script.Parent.getSideLengths)

local RECTANGLE_PERCENT = 0.75

local function isRectangle(hull: { Vector2 }, hullArea: number)
local rectangle = getBoundingBox(hull)
local sides = getSideLengths(rectangle)
local rectangleArea = sides.X * sides.Y

return hullArea / rectangleArea >= RECTANGLE_PERCENT
end

return isRectangle
14 changes: 14 additions & 0 deletions src/isSquare.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
local getBoundingBox = require(script.Parent.getBoundingBox)
local getSideLengths = require(script.Parent.getSideLengths)

local SQUARE_PERCENT = 0.60

local function isSquare(hull: { Vector2 }, hullArea: number)
local rectangle = getBoundingBox(hull)
local sides = getSideLengths(rectangle)
local maxSide = math.max(sides.X, sides.Y)

return hullArea / maxSide^2 >= SQUARE_PERCENT
end

return isSquare
13 changes: 13 additions & 0 deletions src/isTriangle.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
local getLargestTriangle = require(script.Parent.getLargestTriangle)
local getTriangleArea = require(script.Parent.getTriangleArea)

local TRIANGLE_PERCENT = 0.75

local function isTriangle(hull: { Vector2 }, hullArea: number)
local triangle = getLargestTriangle(hull)
local triangleArea = getTriangleArea(unpack(triangle))

return triangleArea / hullArea >= TRIANGLE_PERCENT
end

return isTriangle

0 comments on commit 122de2c

Please sign in to comment.