Skip to content

Instantly share code, notes, and snippets.

@dermotbalson
Created November 16, 2015 07:45
Show Gist options
  • Save dermotbalson/203a525abaafec168577 to your computer and use it in GitHub Desktop.
Save dermotbalson/203a525abaafec168577 to your computer and use it in GitHub Desktop.
Circles
function setup()
FOV=45
perspective(FOV)
PM1=1/projectionMatrix()[1]
ortho()
pos=vec2(100,100) --circle position
camPos=vec2(WIDTH/2,0) --fixed camera
camDir=vec2(-0.5,1):normalize() --camera direction
far=700
fructum=mesh()
local w=far*PM1*vec2(-camDir.y,camDir.x)
fructum.vertices={camPos,camPos+far*camDir-w,camPos+far*camDir+w}
fructum:setColors(color(136, 168, 199, 255))
--radius=50 --collision circle radius
print("Fructum is in blue, pointing up")
print("True tangent is in pink")
print("Fake tangent is in green")
print("Use your finger to drag the circle around")
parameter.number("F",1,3,2.6)
parameter.integer("radius",10,100,50)
end
function draw()
background(150)
fructum:draw()
pushStyle()
stroke(99, 124, 183, 255)
strokeWidth(2)
line(camPos.x,camPos.y,camPos.x+far*camDir.x,camPos.y+far*camDir.y)
popStyle()
DrawCircle()
end
function DrawCircle()
local tangent=GetTangent(pos,radius,camPos,camDir)
--calculate fake tangent
local fake=pos+camDir*radius*F
pushStyle()
if IsVisible(pos,camPos,camDir,radius,far) then fill(255,255,0) else fill(255,255,0,100) end
ellipse(pos.x,pos.y,radius*2)
stroke(195, 72, 169, 255) strokeWidth(2)
line(camPos.x,camPos.y,tangent.x,tangent.y)
stroke(52, 162, 48, 255)
line(camPos.x,camPos.y,fake.x,fake.y)
--ellipse(tangent.x,tangent.y,10)
popStyle()
end
function GetTangent(centre,radius,camPos,camDir)
--calculate offset from centre
local s=(centre.x-camPos.x)/(-centre.y+camPos.y)
local a=(radius/math.sqrt(1+s*s))*vec2(1,s)
--now figure out which side of the circle is closest to the camera direction
--this formula tells which side of a line, a point is on
local d=camPos+camDir*1000
local e=(centre.x-camPos.x)*(d.y-camPos.y)-(centre.y-camPos.y)*(d.x-camPos.x)
if e>0 then return centre-a else return centre+a end --adjust the centre by the offset
end
function touched(t)
pos=vec2(t.x,t.y)
end
--[[
function setup()
FOV=45
perspective(FOV)
PM1=1/projectionMatrix()[1]
ortho()
pos=vec2(100,100) --circle position
camPos=vec2(WIDTH/2,0) --fixed camera
camDir=vec2(0,1)
radius=5000000
n=5000000
t=os.time()
for i=1,n do
a=IsVisible(pos,camPos,camDir,radius)
end
print("True",os.time()-t)
print(n/60/(os.time()-t))
end
function draw()
end
--]]
function IsVisible(pos,camPos,camDir,radius,far)
local px,py,pcx,pcy,pdx,pdy,fx,fy=pos.x,pos.y,camPos.x,camPos.y,camDir.x,camDir.y
--get tangent point
local u=radius*2.6
local tx,ty=px+pdx*u,py+pdy*u --tangent point
--which side of LOS is our circle centre
local dx,dy=pcx+pdx*1000,pcy+pdy*1000
local IsOnLeft=(px-pcx)*(dy-pcy)-(py-pcy)*(dx-pcx)<0
local wx,wy=-far*PM1*pdy,far*PM1*pdx
if IsOnLeft then
fx,fy=pcx+pdx*far+wx,pcy+pdy*far+wy --far left of frustum
return (tx-pcx)*(fy-pcy)-(ty-pcy)*(fx-pcx)>0
else
fx,fy=pcx+pdx*far-wx,pcy+pdy*far-wy --far right of frustum
return (tx-pcx)*(fy-pcy)-(ty-pcy)*(fx-pcx)<0
end
end
function GetTangent(centre,radius,camPos,camDir)
local cx,cy,cpx,cpy,cdx,cdy=centre.x,centre.y,camPos.x,camPos.y,camDir.x,camDir.y
--calculate offset from centre
local s=(cx-cpx)/(-cy+cpy)
local a=(radius/math.sqrt(1+s*s)) --*vec2(1,s)
--now figure out which side of the circle is closest to the camera direction
--this formula tells which side of a line, a point is on
local dx,dy=cpx+cdx*1000,cpy+cdy*1000
local e=(cx-cpx)*(dy-cpy)-(cy-cpy)*(dx-cpx)
if e>0 then return vec2(cx-a,cy-s*a) else return vec2(cx+a,cy+s*a) end --adjust the centre by the offset
end
--[[
function IsVisible(pos,camPos,camLook,radius)
local xDist=DistancePointToLine(pos,camPos,camLook)
return xDist-radius<camPos:dist(pos)/projectionMatrix()[1]*1.1
end
function DistancePointToLine(p,a,b)
b=p+(b-a)*5000
return (p-a):dist(math.max(math.min((p-a):dot(b-a)/(b-a):lenSqr(),1),0)*(b-a))
end
--]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment