Created
November 16, 2015 07:45
-
-
Save dermotbalson/203a525abaafec168577 to your computer and use it in GitHub Desktop.
Circles
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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