Skip to content

Instantly share code, notes, and snippets.

@meta-hub
Created February 25, 2022 10:24
Show Gist options
  • Save meta-hub/c1300902109d58a0025cf5e7ba8e5a19 to your computer and use it in GitHub Desktop.
Save meta-hub/c1300902109d58a0025cf5e7ba8e5a19 to your computer and use it in GitHub Desktop.
--[[
polyzone.lua
Lua implementation of winding number algorithm to determine whether a point is inside a polygon
Credits:
https://gist.github.com/vlasky/d0d1d97af30af3191fc214beaf379acc - Public wn_PnPoly js conversion
http://geomalgorithms.com/a03-_inclusion.html - Original wn_PnPoly function
--]]
local function isLeft(p0,p1,p2)
return ( ( (p1.x - p0.x) * (p2.y - p0.y) ) - ( (p2.x - p0.x) * (p1.y - p0.y) ) )
end
local polyzoneMt = {}
polyzoneMt.__index = polyzoneMt
function polyzoneMt:isPointInside(point)
if point.z then
if point.z > self.maxZ
or point.z < self.minZ
then
return false
end
end
local vs = self.points
local wn = 0
for i=1,#self.points,1 do
local v1 = vs[i]
local v2 = vs[i == #self.points and 1 or i+1]
if v2.y <= point.y then
if v1.y > point.y then
if isLeft(v2,v1,point) > 0 then
wn = wn + 1
end
end
else
if v1.y <= point.y then
if isLeft(v2,v1,point) < 0 then
wn = wn - 1
end
end
end
end
return (wn ~= 0)
end
function polyzoneMt:destroy()
self = nil
end
Polyzone = {}
Polyzone.New = function(points,minZ,maxZ)
return setmetatable({
points = points,
minZ = minZ or -1,
maxZ = maxZ or 1
},polyzoneMt)
end
--[[
Complex polygon example
local points = {
{x = 2, y = 2},
{x = -2, y = 0},
{x = 2, y = -2},
{x = -2, y = -2},
{x = -2, y = 2}
}
local comparePoint = {x = 1, y = 1}
local pz = Polyzone.New(points)
print( pz:isPointInside(comparePoint) )
--]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment