Last active
September 29, 2020 01:40
-
-
Save Anaminus/9469879 to your computer and use it in GitHub Desktop.
DrawArcs
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
-- LOVE2D 0.9.0 | |
-- main.lua | |
-- Left-click somewhere to add point | |
-- Left-click and drag green point to move it | |
-- Right-click green point to remove it | |
-- Left-click and drag red point to modify starting angle | |
-- Backspace to remove all points | |
local Vector2;Vector2 = { | |
new = function(x,y) | |
return setmetatable({x=tonumber(x) or 0,y=tonumber(y) or 0},Vector2.mt) | |
end; | |
mt = { | |
__index = { | |
magnitude = function(v) return math.sqrt(v.x^2 + v.y^2) end; | |
unit = function(v) return Vector2.new(v.x/v:magnitude(),v.y/v:magnitude()) end; | |
dot = function(a,b) return a.x*b.x + a.y*b.y end; | |
perp = function(v) return Vector2.new(v.y,-v.x) end; | |
}; | |
__eq = function(a,b) | |
return a.x == b.x and a.y == b.y | |
end; | |
__add = function(a,b) | |
return Vector2.new(a.x + b.x, a.y + b.y) | |
end; | |
__sub = function(a,b) | |
return Vector2.new(a.x - b.x, a.y - b.y) | |
end; | |
__mul = function(a,b) | |
if type(a) == 'number' then | |
return Vector2.new(a*b.x, a*b.y) | |
elseif type(b) == 'number' then | |
return Vector2.new(a.x*b, a.y*b) | |
else | |
return Vector2.new(a.x*b.x, a.y*b.y) | |
end | |
end; | |
__unm = function(v) | |
return Vector2.new(-v.x,-v.y); | |
end; | |
__div = function(a,b) | |
if type(a) == 'number' then | |
return Vector2.new(a/b.x, a/b.y) | |
elseif type(b) == 'number' then | |
return Vector2.new(a.x/b, a.y/b) | |
else | |
return Vector2.new(a.x/b.x, a.y/b.y) | |
end | |
end; | |
__tostring = function(object) | |
return '[' .. object.x .. ', ' .. object.y .. ']' | |
end; | |
}; | |
} | |
----------------------- | |
local gfx = love.graphics | |
local function normal(n) | |
if n == 0 then return 0 end | |
return n/math.abs(n) | |
end | |
local function drawArc(c,r,a,x,y,s) | |
local p = Vector2.new(-1,0) | |
local q = (x-c):unit() | |
local aq = q:perp():dot(p) | |
local o = math.acos(p:dot(q))*-normal(aq) | |
if a > 0 then o = o + math.pi end | |
for i = 1,s do | |
local a0 = (i-1)/s*a + o | |
local a1 = i/s*a + o | |
gfx.line( | |
c.x + (math.cos(a0) * r), c.y - (math.sin(a0) * r), | |
c.x + (math.cos(a1) * r), c.y - (math.sin(a1) * r) | |
) | |
end | |
end | |
local pressed = false | |
local p = 1 | |
local points = {} | |
local tanAngle = -math.pi/4 | |
local tanPos = Vector2.new() | |
function love.update() | |
if pressed then | |
if p == 0 and points[1] and points[2] then | |
local t = Vector2.new(love.mouse.getPosition()) | |
local x = points[1] | |
local y = points[2] | |
local yx = y-x | |
local yxu = yx:unit() | |
local txu = (t-x):unit() | |
local length = yx:magnitude() | |
local aq = txu:perp():dot(yxu) | |
local a = math.acos(txu:dot(yxu))*normal(aq) | |
tanPos = Vector2.new( | |
yxu.x*math.cos(a) - yxu.y*math.sin(a), | |
yxu.x*math.sin(a) + yxu.y*math.cos(a) | |
)*64 + x | |
tanAngle = a | |
elseif p > 0 and p <= #points then | |
points[p].x,points[p].y = love.mouse.getPosition() | |
end | |
end | |
end | |
function love.draw() | |
gfx.reset() | |
gfx.setLineWidth(6) | |
gfx.setPointSize(12) | |
gfx.setBackgroundColor(102,102,102) | |
for i = 2,#points do | |
local a = points[i-1] | |
local b = points[i] | |
gfx.setColor(0,128,0) | |
gfx.line(a.x,a.y,b.x,b.y) | |
end | |
if #points > 1 then | |
local a = tanAngle | |
for i = 1,#points-1 do | |
local X = points[i] | |
local Y = points[i+1] | |
local Z = points[i+2] | |
local r = (Y-X):magnitude()/2/math.sin(a) | |
local YXu = (Y-X):unit() | |
local a90 = a - math.pi/2 | |
local C = Vector2.new( | |
YXu.x*math.cos(a90) - YXu.y*math.sin(a90), | |
YXu.x*math.sin(a90) + YXu.y*math.cos(a90) | |
)*r + X | |
-- draw circle | |
-- gfx.setColor(128,128,128,128) | |
-- gfx.circle('fill',C.x,C.y,r,100) | |
-- gfx.setColor(77,77,77,128) | |
-- gfx.circle('line',C.x,C.y,r,100) | |
-- draw arc | |
gfx.setColor(255,0,0) | |
drawArc(C,r,a*2,X,Y,100) | |
-- draw radius | |
-- gfx.setColor(0,0,128) | |
-- gfx.line(X.x,X.y,C.x,C.y) | |
-- draw center | |
-- gfx.setColor(0,255,255) | |
-- gfx.point(C.x,C.y) | |
if Z then | |
local YCu = (Y-C):unit()*normal(a) | |
local YCup = YCu:perp() | |
local ZYu = (Z-Y):unit() | |
local aq = YCu:dot(ZYu) | |
a = math.acos(YCup:dot(ZYu))*-normal(aq) | |
-- draw tangent | |
-- local p = YCup*64 + Y | |
-- local q = -YCup*64 + Y | |
-- gfx.setColor(128,0,0) | |
-- gfx.line(p.x,p.y,q.x,q.y) | |
end | |
end | |
end | |
if #points > 1 then | |
local x = points[1] | |
local y = points[2] | |
local yxu = (y-x):unit() | |
tanPos = Vector2.new( | |
yxu.x*math.cos(tanAngle) - yxu.y*math.sin(tanAngle), | |
yxu.x*math.sin(tanAngle) + yxu.y*math.cos(tanAngle) | |
)*64 + x | |
gfx.setLineWidth(6) | |
gfx.setColor(128,0,0) | |
gfx.line(tanPos.x,tanPos.y,x.x,x.y) | |
gfx.setLineWidth(1) | |
gfx.setColor(128,0,0) | |
gfx.circle('fill',tanPos.x,tanPos.y,6) | |
gfx.setColor(255,255,255) | |
gfx.circle('line',tanPos.x,tanPos.y,6) | |
end | |
gfx.setLineWidth(1) | |
for i = 1,#points do | |
local v = points[i] | |
gfx.setColor(0,255,0) | |
gfx.circle('fill',v.x,v.y,6) | |
gfx.setColor(255,255,255) | |
gfx.circle('line',v.x,v.y,6) | |
end | |
end | |
function love.mousepressed(x,y,b) | |
if b ~= 'l' and b ~= 'r' then return end | |
local c = Vector2.new(x,y) | |
if #points > 1 and b == 'l' then | |
if (c-tanPos):magnitude() < 8 then | |
p = 0 | |
pressed = true | |
return | |
end | |
end | |
local n | |
for i = 1,#points do | |
if (c-points[i]):magnitude() < 8 then | |
n = i | |
break | |
end | |
end | |
if b == 'l' then | |
if n then | |
p = n | |
else | |
points[#points+1] = c | |
p = #points | |
end | |
pressed = true | |
elseif b == 'r' then | |
if n and not pressed then | |
table.remove(points,n) | |
end | |
end | |
end | |
function love.mousereleased(x,y,b) | |
if b == 'l' then | |
pressed = false | |
end | |
end | |
function love.keypressed(k) | |
if k == 'backspace' and not pressed then | |
points = {} | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment