WTDKUACNTWB4KD34TZZNPILNX4FQ6MR64XYBAA5GOMICF73WLIAAC
RT6EV6OPUYCXYZOX2PHFXJ7KT77KHNEVINEGQXIQLHQVKPGTN6VQC
NYQ7HD4D5L44UORK52TH7CAEXYN5CE4ZUVLCWMY6XXPYHXVBTGHAC
VHQCNMARPMNBSIUFLJG7HVK4QGDNPCGNVFLHS3I4IGNVSV5MRLYQC
BLWAYPKV3MLDZ4ALXLUJ25AIR6PCIL4RFYNRYLB26GFVC2KQBYBAC
HYEAFRZ2UEKDYTAE2GDQLHEJBPQASP2NDLMXB7F6MTVK2BKOXKEAC
6DE7RBZ6RHNEICJ7EUMCTROK43LW4LYINULIF2QEQOKCXWLUYUXAC
XNFTJHC4QSHNSIWNN7K6QZEZ37GTQYKHS4EPNSVPQCUSWREROGIQC
y = y+15*Zoom
end
if Current_drawing_mode ~= 'rectangle' then
love.graphics.print("* Press 'ctrl+r' to switch to drawing rectangles", 16+30,y, 0, Zoom)
y = y+15*Zoom
end
if Current_drawing_mode ~= 'square' then
love.graphics.print("* Press 'ctrl+s' to switch to drawing squares", 16+30,y, 0, Zoom)
y = y+15*Zoom
end
if Current_drawing_mode ~= 'rectangle' then
love.graphics.print("* Press 'g' to switch to drawing rectangles", 16+30,y, 0, Zoom)
y = y+15*Zoom
end
if Current_drawing_mode ~= 'square' then
love.graphics.print("* Press 'g' to switch to drawing squares", 16+30,y, 0, Zoom)
end
-- are (x3,y3) and (x4,y4) on the same side of the line between (x1,y1) and (x2,y2)
function geom.same_side(x1,y1, x2,y2, x3,y3, x4,y4)
if x1 == x2 then
return math.sign(x3-x1) == math.sign(x4-x1)
end
if y1 == y2 then
return math.sign(y3-y1) == math.sign(y4-y1)
end
local m = (y2-y1)/(x2-x1)
return math.sign(m*(x3-x1) + y1-y3) == math.sign(m*(x4-x1) + y1-y4)
end
function math.sign(x)
if x > 0 then
return 1
elseif x == 0 then
return 0
elseif x < 0 then
return -1
end
elseif shape.mode == 'rectangle' then
local pmx,pmy = love.mouse.getX(), love.mouse.getY()
local first = drawing.points[shape.vertices[1]]
if #shape.vertices == 1 then
love.graphics.line(Drawing.pixels(first.x)+left,Drawing.pixels(first.y)+top, pmx,pmy)
return
end
local second = drawing.points[shape.vertices[2]]
local mx,my = Drawing.coord(pmx-left), Drawing.coord(pmy-top)
local thirdx,thirdy, fourthx,fourthy = Drawing.complete_rectangle(first.x,first.y, second.x,second.y, mx,my)
love.graphics.line(Drawing.pixels(first.x)+left,Drawing.pixels(first.y)+top, Drawing.pixels(second.x)+left,Drawing.pixels(second.y)+top)
love.graphics.line(Drawing.pixels(second.x)+left,Drawing.pixels(second.y)+top, Drawing.pixels(thirdx)+left,Drawing.pixels(thirdy)+top)
love.graphics.line(Drawing.pixels(thirdx)+left,Drawing.pixels(thirdy)+top, Drawing.pixels(fourthx)+left,Drawing.pixels(fourthy)+top)
love.graphics.line(Drawing.pixels(fourthx)+left,Drawing.pixels(fourthy)+top, Drawing.pixels(first.x)+left,Drawing.pixels(first.y)+top)
elseif shape.mode == 'square' then
local pmx,pmy = love.mouse.getX(), love.mouse.getY()
local first = drawing.points[shape.vertices[1]]
if #shape.vertices == 1 then
love.graphics.line(Drawing.pixels(first.x)+left,Drawing.pixels(first.y)+top, pmx,pmy)
return
end
local second = drawing.points[shape.vertices[2]]
local mx,my = Drawing.coord(pmx-left), Drawing.coord(pmy-top)
local thirdx,thirdy, fourthx,fourthy = Drawing.complete_square(first.x,first.y, second.x,second.y, mx,my)
love.graphics.line(Drawing.pixels(first.x)+left,Drawing.pixels(first.y)+top, Drawing.pixels(second.x)+left,Drawing.pixels(second.y)+top)
love.graphics.line(Drawing.pixels(second.x)+left,Drawing.pixels(second.y)+top, Drawing.pixels(thirdx)+left,Drawing.pixels(thirdy)+top)
love.graphics.line(Drawing.pixels(thirdx)+left,Drawing.pixels(thirdy)+top, Drawing.pixels(fourthx)+left,Drawing.pixels(fourthy)+top)
love.graphics.line(Drawing.pixels(fourthx)+left,Drawing.pixels(fourthy)+top, Drawing.pixels(first.x)+left,Drawing.pixels(first.y)+top)
table.insert(Lines.current.shapes, Lines.current.pending)
elseif Lines.current.pending.mode == 'rectangle' then
assert(#Lines.current.pending.vertices <= 2)
if #Lines.current.pending.vertices == 2 then
local mx,my = Drawing.coord(x-16), Drawing.coord(y-Lines.current.y)
if mx >= 0 and mx < 256 and my >= 0 and my < Lines.current.h then
local first = Lines.current.points[Lines.current.pending.vertices[1]]
local second = Lines.current.points[Lines.current.pending.vertices[2]]
local thirdx,thirdy, fourthx,fourthy = Drawing.complete_rectangle(first.x,first.y, second.x,second.y, mx,my)
table.insert(Lines.current.pending.vertices, Drawing.insert_point(Lines.current.points, thirdx,thirdy))
table.insert(Lines.current.pending.vertices, Drawing.insert_point(Lines.current.points, fourthx,fourthy))
table.insert(Lines.current.shapes, Lines.current.pending)
end
else
-- too few points; draw nothing
end
elseif Lines.current.pending.mode == 'square' then
assert(#Lines.current.pending.vertices <= 2)
if #Lines.current.pending.vertices == 2 then
local mx,my = Drawing.coord(x-16), Drawing.coord(y-Lines.current.y)
if mx >= 0 and mx < 256 and my >= 0 and my < Lines.current.h then
local first = Lines.current.points[Lines.current.pending.vertices[1]]
local second = Lines.current.points[Lines.current.pending.vertices[2]]
local thirdx,thirdy, fourthx,fourthy = Drawing.complete_square(first.x,first.y, second.x,second.y, mx,my)
table.insert(Lines.current.pending.vertices, Drawing.insert_point(Lines.current.points, thirdx,thirdy))
table.insert(Lines.current.pending.vertices, Drawing.insert_point(Lines.current.points, fourthx,fourthy))
table.insert(Lines.current.shapes, Lines.current.pending)
end
end
elseif love.mouse.isDown('1') and chord == 'p' and Current_drawing_mode == 'polygon' then
elseif chord == 'C-r' and not love.mouse.isDown('1') then
Current_drawing_mode = 'rectangle'
elseif love.mouse.isDown('1') and chord == 'r' then
Current_drawing_mode = 'rectangle'
local drawing = Drawing.current_drawing()
if drawing.pending.mode == 'freehand' then
drawing.pending.vertices = {Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)}
elseif drawing.pending.mode == 'line' or drawing.pending.mode == 'manhattan' then
if drawing.pending.vertices == nil then
drawing.pending.vertices = {drawing.pending.p1}
end
elseif drawing.pending.mode == 'circle' or drawing.pending.mode == 'arc' then
drawing.pending.vertices = {drawing.pending.center}
end
drawing.pending.mode = 'rectangle'
elseif chord == 'C-s' and not love.mouse.isDown('1') then
Current_drawing_mode = 'square'
elseif love.mouse.isDown('1') and chord == 's' then
Current_drawing_mode = 'square'
local drawing = Drawing.current_drawing()
if drawing.pending.mode == 'freehand' then
drawing.pending.vertices = {Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)}
elseif drawing.pending.mode == 'line' or drawing.pending.mode == 'manhattan' then
if drawing.pending.vertices == nil then
drawing.pending.vertices = {drawing.pending.p1}
end
elseif drawing.pending.mode == 'circle' or drawing.pending.mode == 'arc' then
drawing.pending.vertices = {drawing.pending.center}
end
drawing.pending.mode = 'square'
elseif love.mouse.isDown('1') and chord == 'p' and (Current_drawing_mode == 'polygon' or Current_drawing_mode == 'rectangle' or Current_drawing_mode == 'square') then
end
end
function Drawing.complete_rectangle(firstx,firsty, secondx,secondy, x,y)
if firstx == secondx then
local thirdx = y
local thirdy = secondy
love.graphics.line(Drawing.pixels(secondx)+left,Drawing.pixels(secondy)+top, Drawing.pixels(thirdx)+left,Drawing.pixels(thirdy)+top)
love.graphics.line(Drawing.pixels(thirdx)+left,Drawing.pixels(thirdy)+top, Drawing.pixels(thirdx)+left,Drawing.pixels(firsty)+top)
return thirdx,thirdy, thirdx,firsty
end
if firsty == secondy then
local thirdx = secondx
local thirdy = y
love.graphics.line(Drawing.pixels(secondx)+left,Drawing.pixels(secondy)+top, Drawing.pixels(thirdx)+left,Drawing.pixels(thirdy)+top)
love.graphics.line(Drawing.pixels(thirdx)+left,Drawing.pixels(thirdy)+top, Drawing.pixels(firstx)+left,Drawing.pixels(thirdy)+top)
return
end
local first_slope = (secondy-firsty)/(secondx-firstx)
-- slope of second edge:
-- -1/first_slope
-- equation of line containing the second edge:
-- y-secondy = -1/first_slope*(x-secondx)
-- => 1/first_slope*x + y + (- secondy - secondx/first_slope) = 0
-- now we want to find the point on this line that's closest to the mouse pointer.
-- https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line#Line_defined_by_an_equation
local a = 1/first_slope
local c = -secondy - secondx/first_slope
local thirdx = ((x-a*y) - a*c) / (a*a + 1)
local thirdy = (a*(-x + a*y) - c) / (a*a + 1)
-- slope of third edge = first_slope
-- equation of line containing third edge:
-- y - thirdy = first_slope*(x-thirdx)
-- => -first_slope*x + y + (-thirdy + thirdx*first_slope) = 0
-- now we want to find the point on this line that's closest to the first point
local a = -first_slope
local c = -thirdy + thirdx*first_slope
local fourthx = ((firstx-a*firsty) - a*c) / (a*a + 1)
local fourthy = (a*(-firstx + a*firsty) - c) / (a*a + 1)
return thirdx,thirdy, fourthx,fourthy
end
function Drawing.complete_square(firstx,firsty, secondx,secondy, x,y)
-- use x,y only to decide which side of the first edge to complete the square on
local deltax = secondx-firstx
local deltay = secondy-firsty
local thirdx = secondx+deltay
local thirdy = secondy-deltax
if not geom.same_side(firstx,firsty, secondx,secondy, thirdx,thirdy, x,y) then
deltax = -deltax
deltay = -deltay
thirdx = secondx+deltay
thirdy = secondy-deltax