Last active
April 24, 2024 05:05
-
-
Save akkartik/20a0c7e7589c6179666fc78bc04b28b4 to your computer and use it in GitHub Desktop.
Little UI for compass-and-straightedge constructions using https://love2d.org
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
-- To run: | |
-- Download LÖVE from https://love2d.org | |
-- Download this file to a directory and rename it to `main.lua` | |
-- Run `love .` from that directory. (Replace 'love' with whatever the name of your LÖVE download is.) | |
function love.load() | |
-- maximize window | |
love.window.setMode(0, 0) | |
local width, height, flags = love.window.getMode() | |
-- shrink slightly to account for window decoration | |
width = width-100 | |
height = height-100 | |
love.window.setMode(width, height) | |
love.window.setTitle('Love Geometry') | |
local status_height = 20 | |
UI = { | |
x=5,y=5, w=width-10,h=100, -- menu area | |
status_height=status_height, | |
x2=5,y2=110, w2=width-10, h2=height-status_height-115, -- shapes area | |
-- top-left coords for widgets on screen | |
colorx=25,colory=25, -- toggle between black and red | |
pointx=100,pointy=25, -- point tool | |
linex=175,liney=25, -- line tool | |
radiusx=250,radiusy=25, -- set radius of compass tool | |
compassx=325,compassy=25, -- compass tool | |
} | |
mouse = {x=0,y=0} | |
shapes_committed = {} | |
current_mode = 'line' -- valid modes: dot, line, radius, center, arcbegin, arcend | |
current_red = 0 -- red component of current color (green and blue are always 0) | |
current_radius = 100 | |
current_end_angle = nil | |
pending = {} | |
end | |
function love.mousepressed(x, y, button) | |
if button == 1 then | |
if x>UI.colorx and x<UI.colorx+50 and y>UI.colory and y<UI.colory+50 then current_red = 1-current_red end | |
if x>UI.pointx and x<UI.pointx+50 and y>UI.pointy and y<UI.pointy+50 then current_mode = 'point' end | |
if x>UI.linex and x<UI.linex+50 and y>UI.liney and y<UI.liney+50 then current_mode = 'line' end | |
if x>UI.radiusx and x<UI.radiusx+50 and y>UI.radiusy and y<UI.radiusy+50 then current_mode = 'radius' end | |
if x>UI.compassx and x<UI.compassx+50 and y>UI.compassy and y<UI.compassy+50 then current_mode = 'center' end | |
if x>UI.x2 and x<UI.x2+UI.w2 and y>UI.y2 and y<UI.y2+UI.h2 then | |
if current_mode == 'point' then | |
table.insert(shapes_committed, {shape='point', x=x, y=y, R=current_red}) | |
elseif current_mode == 'line' then | |
pending = {shape = 'line', x1=x,y1=y, R=current_red} | |
elseif current_mode == 'radius' then | |
pending = {shape = 'radius', x1=x,y1=y} | |
elseif current_mode == 'center' then | |
table.insert(shapes_committed, {shape='point', x=x, y=y, R=current_red}) | |
pending = {shape='arc', cx=x,cy=y, r=current_radius, R=current_red} | |
current_mode = 'arcbegin' | |
elseif current_mode == 'arcbegin' then | |
assert(pending.shape == 'arc') | |
pending.s = angle(pending.cx,pending.cy, x,y) | |
current_mode = 'arcend' | |
end | |
end | |
end | |
end | |
function love.mousereleased(x,y, button) | |
if x>UI.x2 and x<UI.x2+UI.w2 and y>UI.y2 and y<UI.y2+UI.h2 then | |
if pending.shape == 'line' then | |
pending.x2 = x | |
pending.y2 = y | |
table.insert(shapes_committed, pending) | |
pending = {} | |
elseif current_mode == 'radius' then | |
-- radius widget doesn't draw anything | |
current_radius = math.dist(pending.x1,pending.y1, x,y) | |
pending = {} | |
current_end_angle = nil | |
elseif current_mode == 'arcend' then | |
pending.e = current_end_angle | |
table.insert(shapes_committed, pending) | |
current_mode = 'center' | |
pending = {} | |
current_end_angle = nil | |
end | |
end | |
end | |
function love.update() | |
mouse.x = love.mouse.getX() | |
mouse.y = love.mouse.getY() | |
end | |
function love.draw() | |
draw_shapes() | |
draw_menu() | |
end | |
function draw_menu() | |
love.graphics.setColor(0.2, 0.2, 0.2) | |
love.graphics.rectangle('fill', UI.x,UI.y, UI.w,UI.h) | |
local width, height, flags = love.window.getMode() | |
love.graphics.setColor(1, 1, 1) | |
love.graphics.print(mouse.x, 5, height-UI.status_height) | |
love.graphics.print("|", 35,height-UI.status_height) | |
love.graphics.print(mouse.y, 45, height-UI.status_height) | |
love.graphics.setColor(current_red, 0, 0) | |
love.graphics.rectangle('fill', UI.colorx,UI.colory, 50,50) | |
if current_mode == 'point' then | |
love.graphics.setColor(1, 1, 1) | |
love.graphics.rectangle('fill', UI.pointx,UI.pointy, 50,50) | |
love.graphics.setColor(current_red, 0, 0) | |
love.graphics.circle('fill', UI.pointx+25,UI.pointy+25, 3) | |
else | |
love.graphics.setColor(0.75, 0.75, 0.75) | |
love.graphics.rectangle('fill', UI.pointx,UI.pointy, 50,50) | |
love.graphics.setColor(0, 0, 0) | |
love.graphics.circle('fill', UI.pointx+25,UI.pointy+25, 3) | |
end | |
if current_mode == 'line' then | |
love.graphics.setColor(1, 1, 1) | |
love.graphics.rectangle('fill', UI.linex,UI.liney, 50,50) | |
love.graphics.setColor(current_red, 0, 0) | |
love.graphics.line(UI.linex+5,UI.liney, UI.linex+45,UI.liney+50) | |
else | |
love.graphics.setColor(0.75, 0.75, 0.75) | |
love.graphics.rectangle('fill', UI.linex,UI.liney, 50,50) | |
love.graphics.setColor(0, 0, 0) | |
love.graphics.line(UI.linex+5,UI.liney, UI.linex+45,UI.liney+50) | |
end | |
if current_mode == 'radius' then | |
love.graphics.setColor(1, 1, 1) | |
love.graphics.rectangle('fill', UI.radiusx,UI.radiusy, 50,50) | |
love.graphics.setColor(current_red, 0, 0) | |
love.graphics.circle('fill', UI.radiusx+10,UI.radiusy+25, 3) | |
love.graphics.line(UI.radiusx+10,UI.radiusy+25, UI.radiusx+40,UI.radiusy+25) | |
love.graphics.circle('fill', UI.radiusx+40,UI.radiusy+25, 3) | |
love.graphics.setColor(0.5, 0.5, 0.5) | |
love.graphics.arc('line', 'open', UI.radiusx+10,UI.radiusy+25, 30, 1/2,-1/2) | |
else | |
love.graphics.setColor(0.75, 0.75, 0.75) | |
love.graphics.rectangle('fill', UI.radiusx,UI.radiusy, 50,50) | |
love.graphics.setColor(0, 0, 0) | |
love.graphics.circle('fill', UI.radiusx+10,UI.radiusy+25, 3) | |
love.graphics.line(UI.radiusx+10,UI.radiusy+25, UI.radiusx+40,UI.radiusy+25) | |
love.graphics.circle('fill', UI.radiusx+40,UI.radiusy+25, 3) | |
love.graphics.setColor(0.5, 0.5, 0.5) | |
love.graphics.arc('line', 'open', UI.radiusx+10,UI.radiusy+25, 30, 1/2,-1/2) | |
end | |
if current_mode == 'center' or current_mode == 'arcbegin' then | |
love.graphics.setColor(1, 1, 1) | |
love.graphics.rectangle('fill', UI.compassx, UI.compassy, 50,50) | |
love.graphics.setColor(0.5, 0.5, 0.5) | |
love.graphics.line(UI.compassx+10,UI.compassy+25, UI.compassx+40,UI.compassy+25) | |
love.graphics.setColor(current_red, 0, 0) | |
love.graphics.arc('line', 'open', UI.compassx+10,UI.compassy+25, 30, 1/2,-1/2) | |
else | |
love.graphics.setColor(0.75, 0.75, 0.75) | |
love.graphics.rectangle('fill', UI.compassx, UI.compassy, 50,50) | |
love.graphics.setColor(0.5, 0.5, 0.5) | |
love.graphics.line(UI.compassx+10,UI.compassy+25, UI.compassx+40,UI.compassy+25) | |
love.graphics.setColor(0, 0, 0) | |
love.graphics.arc('line', 'open', UI.compassx+10,UI.compassy+25, 30, 1/2,-1/2) | |
end | |
end | |
function draw_shapes() | |
love.graphics.setColor(1,1,1) | |
love.graphics.rectangle('fill', UI.x2,UI.y2, UI.w2,UI.h2) | |
for i, v in ipairs(shapes_committed) do | |
love.graphics.setColor(v.R, 0, 0) | |
if v.shape == 'line' then | |
love.graphics.line(v.x1,v.y1, v.x2,v.y2) | |
elseif v.shape == 'point' then | |
love.graphics.circle('fill', v.x,v.y, 3) | |
elseif v.shape == 'arc' then | |
love.graphics.arc('line', 'open', v.cx,v.cy, v.r, v.s,v.e, 360) | |
end | |
end | |
if pending.shape == 'arc' then | |
love.graphics.setColor(0.75, 0.75, 0.75) | |
love.graphics.circle('line', pending.cx,pending.cy, pending.r) | |
end | |
if love.mouse.isDown('1') then | |
if pending.shape == 'line' then | |
love.graphics.setColor(pending.R, 0, 0) | |
love.graphics.line(pending.x1,pending.y1, mouse.x,mouse.y) | |
elseif pending.shape == 'radius' then | |
love.graphics.setColor(0.75, 0.75, 0.75) | |
love.graphics.line(pending.x1,pending.y1, mouse.x,mouse.y) | |
elseif pending.shape == 'arc' then | |
if pending.s then | |
current_end_angle = angle_with_hint(pending.cx,pending.cy, mouse.x,mouse.y, current_end_angle) | |
love.graphics.setColor(pending.R, 0, 0) | |
love.graphics.arc('line', 'open', pending.cx,pending.cy, pending.r, pending.s, current_end_angle, 360) | |
end | |
end | |
end | |
end | |
function angle_with_hint(x1, y1, x2, y2, hint) | |
local result = angle(x1,y1, x2,y2) | |
if hint then | |
-- Smooth the discontinuity where angle goes from positive to negative. | |
-- The hint is a memory of which way we drew it last time. | |
while result > hint+math.pi/10 do | |
result = result-math.pi*2 | |
end | |
while result < hint-math.pi/10 do | |
result = result+math.pi*2 | |
end | |
end | |
return result | |
end | |
-- result is from -π/2 to 3π/2, approximately adding math.atan2 from Lua 5.3 | |
-- (LÖVE is Lua 5.1) | |
function angle(x1,y1, x2,y2) | |
local result = math.atan((y2-y1)/(x2-x1)) | |
if x2 < x1 then | |
result = result+math.pi | |
end | |
return result | |
end | |
function math.dist(x1,y1, x2,y2) return ((x2-x1)^2+(y2-y1)^2)^0.5 end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment