several more modules

[?]
May 18, 2022, 4:18 AM
VHQCNMARPMNBSIUFLJG7HVK4QGDNPCGNVFLHS3I4IGNVSV5MRLYQC

Dependencies

  • [2] JRLBUB6L more intuitive point delete from polygons
  • [3] SYS67ZEJ load/save remaining shapes
  • [4] PLLSUOCI some missing transitions
  • [5] AVDRMDDB bugfix
  • [6] XJ5J7LDI start imposing some organization
  • [7] BLWAYPKV extract a module
  • [8] 7IKRRESB longer names for indices in long loops
  • [9] JVRL5TWL store device-independent coordinates inside drawings
  • [10] KVHUFUFV reorg
  • [11] FJ4L6N74 draw lines by default
  • [12] 6PUNJS5B backspace
  • [13] O2UFJ6G3 switch from freehand to just straight lines
  • [14] IFGAJAF7 add a level of indirection to vertices of shapes
  • [15] GP56QHRH bugfix
  • [16] 5T2E3PDV couple of bugfixes to file-handling
  • [17] VVXVV2D2 change data model; text can now have metadata
  • [18] 5TIFKJ7S handle space key
  • [19] 6LJZN727 handle chords
  • [20] FBDRL6LH delete points or shapes
  • [21] KCIM5UTV revert: back to freehand
  • [22] YKRF5V3Z starting to load/save
  • [23] Z4KNS42N to open a file without a terminal, drag it on!
  • [24] V5TP27FP ctrl-+ and ctrl-- to adjust font size
  • [25] NW7X4AGM much better help color and copy
  • [26] MGOQ5XAV start uppercasing globals
  • [27] HWPK4SMP new mode: manhattan
  • [28] MNWHXPBL more lightweight; select just the stroke at the mouse
  • [29] CXCAERTB icons for current_mode
  • [30] 7Q4B6M2D esc to cancel a shape mid-click
  • [31] T76KKDWZ turn strokes into horizontal and vertical lines
  • [32] FMQ74DP3 new mode: circle
  • [33] T664AOUG make points easier to acquire
  • [34] G77XIN7M selecting a stroke
  • [35] 4NDYV4WD fix 2 bugs in line selection
  • [36] OFA3PRBS autosave on keystrokes
  • [37] 2C7CTIQY make space for multiple kinds of width
  • [38] RJGZD4IN binary search to most natural up/down with proportional fonts
  • [39] JCSLDGAH beginnings of support for multiple shapes
  • [40] SNDZOK6Q slightly less strange now that we have the same two ways to move points as any other operation
  • [41] ICIIP4DB slightly better default sizing of drawings
  • [42] 3XD6M3CF refactor
  • [43] 6J6EEUAY respect zoom when printing online help
  • [44] ZOOY3ME4 new mode: circle arc
  • [45] JS6JSYOT online contextual help
  • [46] 3SYFA5JQ show cursor even on empty lines
  • [47] RXE6NQTN changing your mind mid-shape
  • [48] K6HMLFLZ color close to drawing
  • [49] UTF73CBL reorg
  • [50] YHQC72JX slightly tweak boundary between concerns
  • [51] EDY3RQUL gracefully handle a non-existent filename at the commandline
  • [52] FI6IK76M snap lines to nearby points
  • [53] POT3XFCT rename
  • [54] BULPIBEG beginnings of a module for the text editor
  • [55] VXORMHME delete experimental REPL
  • [56] TRCAEE2A clip drawings inside the border
  • [57] ZD63LJ2T bugfix: keep the click to create a new drawing from creating a new shape in the drawing
  • [58] 2FMZNSD7 experiment: only show drawing borders when they can be edited
  • [59] Z2CJVAPV lighter border for figures
  • [60] ZUOL7X6V move
  • [61] HDCVGN6G save each line's y coordinate, whether it's a drawing or not
  • [62] OTIBCAUJ love2d scaffold
  • [63] R3WSFYGY spacing
  • [64] HRWN5V6J Devine's suggestion to try to live with just freehand
  • [65] IK3N7J3B reset zoom
  • [66] GCUARQ2G bugfix: clipping in line and manhattan mode
  • [67] XX7G2FFJ intermingle freehand line drawings with text
  • [68] 2INHXC3K position cursor by clicking on text
  • [69] H7OEU6WP experimental approach to combining keyboard and mouse while drawing
  • [70] IHG5RXP5 allow text to be typed while mouse hovers over drawing
  • [71] L5USRTY2 inline
  • [72] WAZVXUV2 simplest possible way to straighten strokes
  • [73] NL5J7Z5H new mode: polygon
  • [74] IZZVOCLB confirm that we have access to all of the love API
  • [75] WDWXNW7V slightly strange way to move points
  • [76] LBQAAJN4 load/save freehand strokes
  • [77] 3CS5KKCI up/down cursor movement
  • [78] M36DBSDE bit more polish to help screen
  • [79] D2GCFTTT clean up repl functionality
  • [80] AVQ5MC5D finish uppercasing all globals
  • [81] EFMLTMZG bugfix: restrict strokes to the drawing they started in
  • [82] 6Q6XGOFL little Lua repl on hitting ctrl-r
  • [83] 634QBFQX ctrl- and alt- combinations
  • [*] R5QXEHUI somebody stop me

Change contents

  • edit in main.lua at line 3
    [9.21]
    [9.2]
    require 'file'
  • edit in main.lua at line 7
    [7.65]
    [9.21]
    local geom = require 'geom'
    require 'help'
    require 'icons'
  • replacement in main.lua at line 49
    [9.1241][9.115:157]()
    Current_mode = 'line'
    Previous_mode = nil
    [9.1241]
    [9.3]
    Current_drawing_mode = 'line'
    Previous_drawing_mode = nil
  • edit in main.lua at line 55
    [9.28][9.168:207](),[9.257][9.168:207](),[9.168][9.168:207](),[9.207][9.258:287](),[9.287][9.231:273](),[9.231][9.231:273](),[9.273][9.288:329](),[9.329][9.309:313](),[9.309][9.309:313]()
    function pixels(n) -- parts to pixels
    return n*Drawing_width/256
    end
    function coord(n) -- pixels to parts
    return math.floor(n*256/Drawing_width)
    end
  • replacement in main.lua at line 119
    [9.726][9.399:426]()
    y = y+pixels(line.h)
    [9.468]
    [7.66]
    y = y+Drawing.pixels(line.h)
  • replacement in main.lua at line 133
    [9.60][9.1630:1736]()
    if y >= drawing.y and y < drawing.y + pixels(drawing.h) and x >= 16 and x < 16+Drawing_width then
    [9.60]
    [9.1397]
    if y >= drawing.y and y < drawing.y + Drawing.pixels(drawing.h) and x >= 16 and x < 16+Drawing_width then
  • replacement in main.lua at line 135
    [9.1450][9.351:471]()
    table.insert(drawing.pending.points, {x=coord(love.mouse.getX()-16), y=coord(love.mouse.getY()-drawing.y)})
    [9.1450]
    [9.3]
    table.insert(drawing.pending.points, {x=Drawing.coord(love.mouse.getX()-16), y=Drawing.coord(love.mouse.getY()-drawing.y)})
  • replacement in main.lua at line 137
    [9.56][9.56:114]()
    local mx,my = coord(x-16), coord(y-drawing.y)
    [9.56]
    [9.114]
    local mx,my = Drawing.coord(x-16), Drawing.coord(y-drawing.y)
  • replacement in main.lua at line 144
    [9.1677][9.1737:1774]()
    elseif Current_mode == 'move' then
    [9.1677]
    [9.468]
    elseif Current_drawing_mode == 'move' then
  • replacement in main.lua at line 147
    [9.149][9.1775:1877](),[9.1877][9.246:298](),[9.246][9.246:298]()
    if y >= drawing.y and y < drawing.y + pixels(drawing.h) and x >= 16 and x < 16+Drawing_width then
    local mx,my = coord(x-16), coord(y-drawing.y)
    [9.149]
    [9.298]
    if y >= drawing.y and y < drawing.y + Drawing.pixels(drawing.h) and x >= 16 and x < 16+Drawing_width then
    local mx,my = Drawing.coord(x-16), Drawing.coord(y-drawing.y)
  • replacement in main.lua at line 168
    [9.132][9.2016:2333](),[9.2333][9.444:526](),[9.444][9.444:526](),[9.526][9.2334:2434](),[9.2434][9.626:708](),[9.626][9.626:708](),[9.708][9.2435:2542](),[9.2542][9.815:897](),[9.815][9.815:897](),[9.897][9.2543:2601]()
    if y >= drawing.y and y < drawing.y + pixels(drawing.h) and x >= 16 and x < 16+Drawing_width then
    if Current_mode == 'freehand' then
    drawing.pending = {mode=Current_mode, points={{x=coord(x-16), y=coord(y-drawing.y)}}}
    elseif Current_mode == 'line' or Current_mode == 'manhattan' then
    local j = insert_point(drawing.points, coord(x-16), coord(y-drawing.y))
    drawing.pending = {mode=Current_mode, p1=j}
    elseif Current_mode == 'polygon' then
    local j = insert_point(drawing.points, coord(x-16), coord(y-drawing.y))
    drawing.pending = {mode=Current_mode, vertices={j}}
    elseif Current_mode == 'circle' then
    local j = insert_point(drawing.points, coord(x-16), coord(y-drawing.y))
    drawing.pending = {mode=Current_mode, center=j}
    [9.132]
    [9.955]
    if y >= drawing.y and y < drawing.y + Drawing.pixels(drawing.h) and x >= 16 and x < 16+Drawing_width then
    if Current_drawing_mode == 'freehand' then
    drawing.pending = {mode=Current_drawing_mode, points={{x=Drawing.coord(x-16), y=Drawing.coord(y-drawing.y)}}}
    elseif Current_drawing_mode == 'line' or Current_drawing_mode == 'manhattan' then
    local j = Drawing.insert_point(drawing.points, Drawing.coord(x-16), Drawing.coord(y-drawing.y))
    drawing.pending = {mode=Current_drawing_mode, p1=j}
    elseif Current_drawing_mode == 'polygon' then
    local j = Drawing.insert_point(drawing.points, Drawing.coord(x-16), Drawing.coord(y-drawing.y))
    drawing.pending = {mode=Current_drawing_mode, vertices={j}}
    elseif Current_drawing_mode == 'circle' then
    local j = Drawing.insert_point(drawing.points, Drawing.coord(x-16), Drawing.coord(y-drawing.y))
    drawing.pending = {mode=Current_drawing_mode, center=j}
  • replacement in main.lua at line 188
    [9.1626][9.2602:2692]()
    if Current_mode == 'move' then
    Current_mode = Previous_mode
    Previous_mode = nil
    [9.1626]
    [9.570]
    if Current_drawing_mode == 'move' then
    Current_drawing_mode = Previous_drawing_mode
    Previous_drawing_mode = nil
  • replacement in main.lua at line 197
    [9.809][9.809:869]()
    local mx,my = coord(x-16), coord(y-Lines.current.y)
    [9.809]
    [9.869]
    local mx,my = Drawing.coord(x-16), Drawing.coord(y-Lines.current.y)
  • replacement in main.lua at line 199
    [9.943][9.943:1005]()
    local j = insert_point(Lines.current.points, mx,my)
    [9.943]
    [9.1005]
    local j = Drawing.insert_point(Lines.current.points, mx,my)
  • replacement in main.lua at line 205
    [9.1239][9.1239:1299]()
    local mx,my = coord(x-16), coord(y-Lines.current.y)
    [9.1239]
    [9.1299]
    local mx,my = Drawing.coord(x-16), Drawing.coord(y-Lines.current.y)
  • replacement in main.lua at line 208
    [9.583][9.1374:1441]()
    local j = insert_point(Lines.current.points, mx, p1.y)
    [9.583]
    [9.1441]
    local j = Drawing.insert_point(Lines.current.points, mx, p1.y)
  • replacement in main.lua at line 211
    [9.706][9.1483:1550]()
    local j = insert_point(Lines.current.points, p1.x, my)
    [9.706]
    [9.1550]
    local j = Drawing.insert_point(Lines.current.points, p1.x, my)
  • replacement in main.lua at line 215
    [9.1660][9.1660:1740]()
    love.mouse.setPosition(16+pixels(p2.x), Lines.current.y+pixels(p2.y))
    [9.1660]
    [9.1740]
    love.mouse.setPosition(16+Drawing.pixels(p2.x), Lines.current.y+Drawing.pixels(p2.y))
  • replacement in main.lua at line 219
    [9.1867][9.1867:1927]()
    local mx,my = coord(x-16), coord(y-Lines.current.y)
    [9.1867]
    [9.1927]
    local mx,my = Drawing.coord(x-16), Drawing.coord(y-Lines.current.y)
  • replacement in main.lua at line 221
    [9.2001][9.2001:2063]()
    local j = insert_point(Lines.current.points, mx,my)
    [9.2001]
    [9.2063]
    local j = Drawing.insert_point(Lines.current.points, mx,my)
  • replacement in main.lua at line 226
    [9.2255][9.2255:2315]()
    local mx,my = coord(x-16), coord(y-Lines.current.y)
    [9.2255]
    [9.2315]
    local mx,my = Drawing.coord(x-16), Drawing.coord(y-Lines.current.y)
  • replacement in main.lua at line 233
    [9.2665][9.2665:2725]()
    local mx,my = coord(x-16), coord(y-Lines.current.y)
    [9.2665]
    [9.2725]
    local mx,my = Drawing.coord(x-16), Drawing.coord(y-Lines.current.y)
  • replacement in main.lua at line 236
    [9.2875][9.2875:2994]()
    Lines.current.pending.end_angle = angle_with_hint(center.x,center.y, mx,my, Lines.current.pending.end_angle)
    [9.2875]
    [9.2994]
    Lines.current.pending.end_angle = geom.angle_with_hint(center.x,center.y, mx,my, Lines.current.pending.end_angle)
  • edit in main.lua at line 246
    [9.2746][9.55:61](),[9.3157][9.55:61](),[9.55][9.55:61](),[9.61][9.2109:2114](),[9.190][9.2109:2114](),[9.2109][9.2109:2114](),[9.469][9.762:797](),[9.39][9.797:832](),[9.797][9.797:832](),[9.832][9.35:64](),[9.64][9.874:955](),[9.142][9.874:955](),[9.874][9.874:955](),[9.955][9.65:229](),[9.229][9.955:1006](),[9.955][9.955:1006](),[9.1006][9.2424:2688](),[9.2424][9.2424:2688](),[9.2688][9.696:760](),[9.760][9.1007:1182](),[9.2723][9.1007:1182](),[9.1182][9.595:1078](),[9.1078][9.614:798](),[9.798][9.467:694](),[9.694][9.341:379](),[9.379][9.694:741](),[9.694][9.694:741](),[9.741][9.2834:2845](),[9.798][9.2834:2845](),[9.1078][9.2834:2845](),[9.1182][9.2834:2845](),[9.2834][9.2834:2845](),[9.2845][9.1183:1262](),[9.1262][9.2890:2925](),[9.2890][9.2890:2925](),[9.2925][9.1263:1304](),[9.1304][9.2957:2992](),[9.2957][9.2957:2992](),[9.2992][9.1305:1345](),[9.1345][9.1045:1300](),[9.1300][9.761:923](),[9.1441][9.761:923](),[9.923][9.1301:1383](),[9.1383][9.923:1180](),[9.923][9.923:1180](),[9.1180][9.1079:1535](),[9.1535][9.799:1205](),[9.1205][9.742:1239]()
    end
    end
    function insert_point(points, x,y)
    for i,point in ipairs(points) do
    if near(point, x,y) then
    return i
    end
    end
    table.insert(points, {x=x, y=y})
    return #points
    end
    function near(point, x,y)
    local px,py = pixels(x),pixels(y)
    local cx,cy = pixels(point.x), pixels(point.y)
    return (cx-px)*(cx-px) + (cy-py)*(cy-py) < 16
    end
    function draw_shape(left,top, drawing, shape)
    if shape.mode == 'freehand' then
    local prev = nil
    for _,point in ipairs(shape.points) do
    if prev then
    love.graphics.line(pixels(prev.x)+left,pixels(prev.y)+top, pixels(point.x)+left,pixels(point.y)+top)
    end
    prev = point
    end
    elseif shape.mode == 'line' or shape.mode == 'manhattan' then
    local p1 = drawing.points[shape.p1]
    local p2 = drawing.points[shape.p2]
    love.graphics.line(pixels(p1.x)+left,pixels(p1.y)+top, pixels(p2.x)+left,pixels(p2.y)+top)
    elseif shape.mode == 'polygon' then
    local prev = nil
    for _,point in ipairs(shape.vertices) do
    local curr = drawing.points[point]
    if prev then
    love.graphics.line(pixels(prev.x)+left,pixels(prev.y)+top, pixels(curr.x)+left,pixels(curr.y)+top)
    end
    prev = curr
    end
    -- close the loop
    local curr = drawing.points[shape.vertices[1]]
    love.graphics.line(pixels(prev.x)+left,pixels(prev.y)+top, pixels(curr.x)+left,pixels(curr.y)+top)
    elseif shape.mode == 'circle' then
    local center = drawing.points[shape.center]
    love.graphics.circle('line', pixels(center.x)+left,pixels(center.y)+top, pixels(shape.radius))
    elseif shape.mode == 'arc' then
    local center = drawing.points[shape.center]
    love.graphics.arc('line', 'open', pixels(center.x)+left,pixels(center.y)+top, pixels(shape.radius), shape.start_angle, shape.end_angle, 360)
    elseif shape.mode == 'deleted' then
    else
    print(shape.mode)
    assert(false)
    end
    end
    function draw_pending_shape(left,top, drawing)
    local shape = drawing.pending
    if shape.mode == 'freehand' then
    draw_shape(left,top, drawing, shape)
    elseif shape.mode == 'line' then
    local p1 = drawing.points[shape.p1]
    local mx,my = coord(love.mouse.getX()-16), coord(love.mouse.getY()-drawing.y)
    if mx < 0 or mx >= 256 or my < 0 or my >= drawing.h then
    return
    end
    love.graphics.line(pixels(p1.x)+left,pixels(p1.y)+top, pixels(mx)+left,pixels(my)+top)
    elseif shape.mode == 'manhattan' then
    local p1 = drawing.points[shape.p1]
    local mx,my = coord(love.mouse.getX()-16), coord(love.mouse.getY()-drawing.y)
    if mx < 0 or mx >= 256 or my < 0 or my >= drawing.h then
    return
    end
    if math.abs(mx-p1.x) > math.abs(my-p1.y) then
    love.graphics.line(pixels(p1.x)+left,pixels(p1.y)+top, pixels(mx)+left,pixels(p1.y)+top)
    else
    love.graphics.line(pixels(p1.x)+left,pixels(p1.y)+top, pixels(p1.x)+left,pixels(my)+top)
    end
    elseif shape.mode == 'polygon' then
    -- don't close the loop on a pending polygon
    local prev = nil
    for _,point in ipairs(shape.vertices) do
    local curr = drawing.points[point]
    if prev then
    love.graphics.line(pixels(prev.x)+left,pixels(prev.y)+top, pixels(curr.x)+left,pixels(curr.y)+top)
    end
    prev = curr
    end
    love.graphics.line(pixels(prev.x)+left,pixels(prev.y)+top, love.mouse.getX(),love.mouse.getY())
    elseif shape.mode == 'circle' then
    local center = drawing.points[shape.center]
    local mx,my = coord(love.mouse.getX()-16), coord(love.mouse.getY()-drawing.y)
    if mx < 0 or mx >= 256 or my < 0 or my >= drawing.h then
    return
    end
    local cx,cy = pixels(center.x)+left, pixels(center.y)+top
    love.graphics.circle('line', cx,cy, math.dist(cx,cy, love.mouse.getX(),love.mouse.getY()))
    elseif shape.mode == 'arc' then
    local center = drawing.points[shape.center]
    local mx,my = coord(love.mouse.getX()-16), coord(love.mouse.getY()-drawing.y)
    if mx < 0 or mx >= 256 or my < 0 or my >= drawing.h then
    return
    end
    shape.end_angle = angle_with_hint(center.x,center.y, mx,my, shape.end_angle)
    local cx,cy = pixels(center.x)+left, pixels(center.y)+top
    love.graphics.arc('line', 'open', cx,cy, pixels(shape.radius), shape.start_angle, shape.end_angle, 360)
  • edit in main.lua at line 249
    [9.3121][9.1442:1481](),[9.1481][9.3151:3186](),[9.3151][9.3151:3186](),[9.3186][9.1482:1526](),[9.1526][9.3221:3256](),[9.3221][9.3221:3256](),[9.3256][9.1527:1567](),[9.1567][9.1181:1299](),[9.1299][9.1536:1617](),[9.1617][9.1206:1352](),[9.1352][9.1240:1549](),[9.1549][9.380:418](),[9.418][9.3287:3294](),[9.1299][9.3287:3294](),[9.1352][9.3287:3294](),[9.1549][9.3287:3294](),[9.1567][9.3287:3294](),[9.1617][9.3287:3294](),[9.3287][9.3287:3294](),[9.3294][9.1300:1322](),[9.1322][9.3294:3323](),[9.3294][9.3294:3323](),[9.3323][9.1568:1610](),[9.1610][9.442:455](),[9.442][9.442:455](),[9.455][9.3324:3361](),[9.3361][9.485:502](),[9.485][9.485:502](),[9.502][9.1611:1664](),[9.1664][9.567:644](),[9.567][9.567:644](),[9.644][9.1665:1927](),[9.1927][9.74:101](),[9.74][9.74:101](),[9.101][9.1928:1956](),[9.1956][9.740:760](),[9.740][9.740:760](),[9.760][9.102:122](),[9.122][9.780:864](),[9.780][9.780:864](),[9.864][9.1957:2030](),[9.2030][9.961:1044](),[9.961][9.961:1044](),[9.1044][9.2031:2066](),[9.2066][9.1091:1128](),[9.1091][9.1091:1128](),[9.1128][9.1618:1934](),[9.1934][9.1550:1633](),[9.1691][9.1691:2004]()
    function on_shape(x,y, drawing, shape)
    if shape.mode == 'freehand' then
    return on_freehand(x,y, drawing, shape)
    elseif shape.mode == 'line' then
    return on_line(x,y, drawing, shape)
    elseif shape.mode == 'manhattan' then
    return x == drawing.points[shape.p1].x or y == drawing.points[shape.p1].y
    elseif shape.mode == 'polygon' then
    return on_polygon(x,y, drawing, shape)
    elseif shape.mode == 'circle' then
    local center = drawing.points[shape.center]
    return math.dist(center.x,center.y, x,y) == shape.radius
    elseif shape.mode == 'arc' then
    local center = drawing.points[shape.center]
    local dist = math.dist(center.x,center.y, x,y)
    if dist < shape.radius*0.95 or dist > shape.radius*1.05 then
    return false
    end
    return angle_between(center.x,center.y, x,y, shape.start_angle,shape.end_angle)
    elseif shape.mode == 'deleted' then
    else
    print(shape.mode)
    assert(false)
    end
    end
    function on_freehand(x,y, drawing, shape)
    local prev
    for _,p in ipairs(shape.points) do
    if prev then
    if on_line(x,y, drawing, {p1=prev, p2=p}) then
    return true
    end
    end
    prev = p
    end
    return false
    end
    function on_line(x,y, drawing, shape)
    local p1,p2
    if type(shape.p1) == 'number' then
    p1 = drawing.points[shape.p1]
    p2 = drawing.points[shape.p2]
    else
    p1 = shape.p1
    p2 = shape.p2
    end
    if p1.x == p2.x then
    if math.abs(p1.x-x) > 5 then
    return false
    end
    local y1,y2 = p1.y,p2.y
    if y1 > y2 then
    y1,y2 = y2,y1
    end
    return y >= y1 and y <= y2
    end
    -- has the right slope and intercept
    local m = (p2.y - p1.y) / (p2.x - p1.x)
    local yp = p1.y + m*(x-p1.x)
    if yp < 0.95*y or yp > 1.05*y then
    return false
    end
    -- between endpoints
    local k = (x-p1.x) / (p2.x-p1.x)
    return k > -0.05 and k < 1.05
    end
    function on_polygon(x,y, drawing, shape)
    local prev
    for _,p in ipairs(shape.vertices) do
    if prev then
    if on_line(x,y, drawing, {p1=prev, p2=p}) then
    return true
    end
    end
    prev = p
    end
    return on_line(x,y, drawing, {p1=shape.vertices[1], p2=shape.vertices[#shape.vertices]})
    end
    function angle_between(x1,y1, x2,y2, s,e)
    local angle = math.angle(x1,y1, x2,y2)
    if s > e then
    s,e = e,s
    end
    -- I'm not sure this is right or ideal..
    angle = angle-math.pi*2
    if s <= angle and angle <= e then
    return true
    end
    angle = angle+math.pi*2
    if s <= angle and angle <= e then
    return true
    end
    angle = angle+math.pi*2
    return s <= angle and angle <= e
    end
  • replacement in main.lua at line 359
    [9.61][9.61:99]()
    local drawing = current_drawing()
    [9.61]
    [9.99]
    local drawing = Drawing.current_drawing()
  • replacement in main.lua at line 362
    [9.559][9.5548:5578]()
    Current_mode = 'freehand'
    [9.559]
    [9.560]
    Current_drawing_mode = 'freehand'
  • replacement in main.lua at line 364
    [9.620][9.5579:5608]()
    Current_mode = 'polygon'
    [9.620]
    [9.32]
    Current_drawing_mode = 'polygon'
  • replacement in main.lua at line 366
    [9.86][9.5609:5638](),[9.5638][9.87:125](),[9.1993][9.87:125]()
    Current_mode = 'polygon'
    local drawing = current_drawing()
    [9.86]
    [4.2]
    Current_drawing_mode = 'polygon'
    local drawing = Drawing.current_drawing()
  • replacement in main.lua at line 369
    [4.49][4.49:171]()
    drawing.pending.vertices = {insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)}
    [4.49]
    [4.171]
    drawing.pending.vertices = {Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)}
  • replacement in main.lua at line 378
    [9.407][9.5639:5723](),[9.5723][9.2077:2247](),[9.2077][9.2077:2247]()
    elseif love.mouse.isDown('1') and chord == 'p' and Current_mode == 'polygon' then
    local drawing = current_drawing()
    local mx,my = coord(love.mouse.getX()-16), coord(love.mouse.getY()-drawing.y)
    local j = insert_point(drawing.points, mx,my)
    [9.407]
    [9.2247]
    elseif love.mouse.isDown('1') and chord == 'p' and Current_drawing_mode == 'polygon' then
    local drawing = Drawing.current_drawing()
    local mx,my = Drawing.coord(love.mouse.getX()-16), Drawing.coord(love.mouse.getY()-drawing.y)
    local j = Drawing.insert_point(drawing.points, mx,my)
  • replacement in main.lua at line 384
    [9.681][9.5724:5835](),[9.5835][9.2088:2126](),[9.2088][9.2088:2126]()
    Current_mode = 'circle'
    elseif love.mouse.isDown('1') and chord == 'a' and Current_mode == 'circle' then
    local drawing = current_drawing()
    [9.681]
    [9.2126]
    Current_drawing_mode = 'circle'
    elseif love.mouse.isDown('1') and chord == 'a' and Current_drawing_mode == 'circle' then
    local drawing = Drawing.current_drawing()
  • replacement in main.lua at line 388
    [9.2159][9.2159:2291]()
    local mx,my = coord(love.mouse.getX()-16), coord(love.mouse.getY()-drawing.y)
    local j = insert_point(drawing.points, mx,my)
    [9.2159]
    [9.2291]
    local mx,my = Drawing.coord(love.mouse.getX()-16), Drawing.coord(love.mouse.getY()-drawing.y)
    local j = Drawing.insert_point(drawing.points, mx,my)
  • replacement in main.lua at line 392
    [9.2414][9.2414:2485]()
    drawing.pending.start_angle = math.angle(center.x,center.y, mx,my)
    [9.2414]
    [9.408]
    drawing.pending.start_angle = geom.angle(center.x,center.y, mx,my)
  • replacement in main.lua at line 394
    [9.462][9.5836:5864](),[9.5864][9.490:528](),[9.490][9.490:528]()
    Current_mode = 'circle'
    local drawing = current_drawing()
    [9.462]
    [4.370]
    Current_drawing_mode = 'circle'
    local drawing = Drawing.current_drawing()
  • replacement in main.lua at line 397
    [4.417][4.417:535]()
    drawing.pending.center = insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)
    [4.417]
    [4.535]
    drawing.pending.center = Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)
  • replacement in main.lua at line 405
    [9.195][9.5865:5891](),[9.5891][9.221:259](),[9.221][9.221:259]()
    Current_mode = 'line'
    local drawing = current_drawing()
    [9.195]
    [9.775]
    Current_drawing_mode = 'line'
    local drawing = Drawing.current_drawing()
  • replacement in main.lua at line 408
    [9.822][9.822:936]()
    drawing.pending.p1 = insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)
    [9.822]
    [9.936]
    drawing.pending.p1 = Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)
  • replacement in main.lua at line 416
    [9.906][9.5892:5918](),[9.5918][8.381:433]()
    Current_mode = 'line'
    local drawing,_,shape = select_shape_at_mouse()
    [9.906]
    [9.958]
    Current_drawing_mode = 'line'
    local drawing,_,shape = Drawing.select_shape_at_mouse()
  • replacement in main.lua at line 422
    [9.1377][9.5919:5950](),[9.5950][9.1408:1454](),[9.1408][9.1408:1454]()
    Current_mode = 'manhattan'
    local drawing = select_drawing_at_mouse()
    [9.1377]
    [4.728]
    Current_drawing_mode = 'manhattan'
    local drawing = Drawing.select_drawing_at_mouse()
  • replacement in main.lua at line 425
    [4.775][4.775:889]()
    drawing.pending.p1 = insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)
    [4.775]
    [4.889]
    drawing.pending.p1 = Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)
  • replacement in main.lua at line 435
    [9.742][9.5951:5982](),[9.5982][8.434:486]()
    Current_mode = 'manhattan'
    local drawing,_,shape = select_shape_at_mouse()
    [9.742]
    [9.92]
    Current_drawing_mode = 'manhattan'
    local drawing,_,shape = Drawing.select_shape_at_mouse()
  • replacement in main.lua at line 441
    [9.803][8.487:539]()
    local drawing,_,shape = select_shape_at_mouse()
    [9.803]
    [9.84]
    local drawing,_,shape = Drawing.select_shape_at_mouse()
  • replacement in main.lua at line 446
    [9.864][9.449:497]()
    local drawing,_,p = select_point_at_mouse()
    [9.864]
    [9.910]
    local drawing,_,p = Drawing.select_point_at_mouse()
  • replacement in main.lua at line 448
    [9.930][9.5983:6106]()
    Previous_mode = Current_mode
    Current_mode = 'move'
    drawing.pending = {mode=Current_mode, target_point=p}
    [9.930]
    [9.5279]
    Previous_drawing_mode = Current_drawing_mode
    Current_drawing_mode = 'move'
    drawing.pending = {mode=Current_drawing_mode, target_point=p}
  • replacement in main.lua at line 454
    [9.471][9.498:546]()
    local drawing,_,p = select_point_at_mouse()
    [9.471]
    [9.517]
    local drawing,_,p = Drawing.select_point_at_mouse()
  • replacement in main.lua at line 456
    [9.537][9.6107:6230]()
    Previous_mode = Current_mode
    Current_mode = 'move'
    drawing.pending = {mode=Current_mode, target_point=p}
    [9.537]
    [9.5310]
    Previous_drawing_mode = Current_drawing_mode
    Current_drawing_mode = 'move'
    drawing.pending = {mode=Current_drawing_mode, target_point=p}
  • replacement in main.lua at line 462
    [9.615][9.615:663]()
    local drawing,i,p = select_point_at_mouse()
    [9.615]
    [9.663]
    local drawing,i,p = Drawing.select_point_at_mouse()
  • replacement in main.lua at line 465
    [9.730][9.730:771]()
    if contains_point(shape, i) then
    [9.730]
    [2.3]
    if Drawing.contains_point(shape, i) then
  • replacement in main.lua at line 480
    [9.873][8.540:592]()
    local drawing,_,shape = select_shape_at_mouse()
    [9.873]
    [9.925]
    local drawing,_,shape = Drawing.select_shape_at_mouse()
  • replacement in main.lua at line 485
    [9.317][9.317:363]()
    local drawing = select_drawing_at_mouse()
    [9.317]
    [9.363]
    local drawing = Drawing.select_drawing_at_mouse()
  • edit in main.lua at line 493
    [9.146][9.146:156](),[9.156][9.533:552](),[9.576][9.533:552](),[9.803][9.803:882](),[9.882][9.5377:5413](),[9.5413][9.3056:3094](),[9.918][9.3056:3094](),[9.3094][9.6279:6383](),[9.994][9.1054:1087](),[9.6383][9.1054:1087](),[9.1054][9.1054:1087](),[9.1087][9.126:134](),[9.126][9.126:134](),[9.134][9.119:125](),[9.119][9.119:125](),[9.125][9.1088:1101](),[9.1101][9.125:163](),[9.125][9.125:163](),[9.163][9.5414:5450](),[9.5450][9.3095:3133](),[9.199][9.3095:3133](),[9.3133][9.236:292](),[9.236][9.236:292](),[9.292][9.6384:6488](),[9.6488][9.1094:1180](),[9.1094][9.1094:1180](),[9.1180][9.384:433](),[9.1354][9.384:433](),[9.384][9.384:433](),[9.433][9.1384:1408](),[9.1408][9.975:1025](),[9.766][9.507:542](),[9.1025][9.507:542](),[9.1067][9.507:542](),[9.1399][9.507:542](),[9.3460][9.507:542](),[9.507][9.507:542](),[9.542][9.1073:1161](),[9.1161][9.5451:5487](),[9.5487][9.3134:3172](),[9.1197][9.3134:3172](),[9.3172][9.1234:1290](),[9.1234][9.1234:1290](),[9.1290][9.6489:6593](),[9.6593][9.1389:1475](),[9.1389][9.1389:1475](),[9.1475][9.1026:1075](),[9.1075][9.1524:1585](),[9.1524][9.1524:1585](),[9.1585][9.1076:1111](),[9.542][9.448:492](),[9.1111][9.448:492](),[9.1618][9.448:492](),[9.448][9.448:492](),[9.185][9.601:607](),[9.324][9.601:607](),[9.492][9.601:607](),[9.1135][9.601:607](),[9.601][9.601:607](),[9.607][9.1068:1073](),[9.1073][9.1526:1561](),[9.1561][9.5488:5524](),[9.5524][9.3173:3211](),[9.1597][9.3173:3211](),[9.3211][9.1634:1690](),[9.1634][9.1634:1690](),[9.1690][9.6594:6698](),[9.6698][9.1789:1812](),[9.1789][9.1789:1812]()
    end
    end
    end
    end
    function current_drawing()
    local x, y = love.mouse.getX(), love.mouse.getY()
    for _,drawing in ipairs(Lines) do
    if drawing.mode == 'drawing' then
    if y >= drawing.y and y < drawing.y + pixels(drawing.h) and x >= 16 and x < 16+Drawing_width then
    return drawing
    end
    end
    end
    return nil
    end
    function select_shape_at_mouse()
    for _,drawing in ipairs(Lines) do
    if drawing.mode == 'drawing' then
    local x, y = love.mouse.getX(), love.mouse.getY()
    if y >= drawing.y and y < drawing.y + pixels(drawing.h) and x >= 16 and x < 16+Drawing_width then
    local mx,my = coord(love.mouse.getX()-16), coord(love.mouse.getY()-drawing.y)
    for i,shape in ipairs(drawing.shapes) do
    assert(shape)
    if on_shape(mx,my, drawing, shape) then
    return drawing,i,shape
    end
    end
    end
    end
    end
    end
    function select_point_at_mouse()
    for _,drawing in ipairs(Lines) do
    if drawing.mode == 'drawing' then
    local x, y = love.mouse.getX(), love.mouse.getY()
    if y >= drawing.y and y < drawing.y + pixels(drawing.h) and x >= 16 and x < 16+Drawing_width then
    local mx,my = coord(love.mouse.getX()-16), coord(love.mouse.getY()-drawing.y)
    for i,point in ipairs(drawing.points) do
    assert(point)
    if near(point, mx,my) then
    return drawing,i,point
    end
    end
    end
    end
    end
    end
    function select_drawing_at_mouse()
    for _,drawing in ipairs(Lines) do
    if drawing.mode == 'drawing' then
    local x, y = love.mouse.getX(), love.mouse.getY()
    if y >= drawing.y and y < drawing.y + pixels(drawing.h) and x >= 16 and x < 16+Drawing_width then
    return drawing
  • edit in main.lua at line 494
    [9.1822][9.1822:1841](),[9.1841][9.1112:1202](),[9.1202][5.2:66](),[5.66][9.1270:1619](),[9.1270][9.1270:1619](),[9.1619][5.67:89](),[5.89][9.1619:1648](),[9.1619][9.1619:1648](),[9.1648][9.2255:2293](),[9.1841][9.2255:2293](),[9.1073][9.2255:2293](),[9.2293][9.1114:1353](),[9.3490][9.1114:1353](),[9.1114][9.1114:1353](),[9.1353][9.3491:3548](),[9.3548][9.2294:2480](),[9.1401][9.152:157](),[9.2480][9.152:157](),[9.3696][9.152:157](),[9.826][9.152:157](),[9.157][9.3697:3742](),[9.3742][9.2481:2522](),[9.2522][9.3774:3870](),[9.3774][9.3774:3870](),[9.3870][9.2523:2667](),[9.859][9.445:452](),[9.1587][9.445:452](),[9.2667][9.445:452](),[9.3962][9.445:452](),[9.445][9.445:452](),[9.452][9.2668:2684](),[9.884][9.505:511](),[9.1641][9.505:511](),[9.2684][9.505:511](),[9.3987][9.505:511](),[9.505][9.505:511](),[9.511][9.325:330](),[9.826][9.325:330](),[9.607][9.325:330](),[9.330][9.135:160](),[9.160][9.3988:4023](),[9.4023][9.160:175](),[9.160][9.160:175](),[9.175][9.4024:4155](),[9.4155][9.278:342](),[9.278][9.278:342]()
    end
    end
    end
    function contains_point(shape, p)
    if shape.mode == 'freehand' then
    -- not supported
    elseif shape.mode == 'line' or shape.mode == 'manhattan' then
    return shape.p1 == p or shape.p2 == p
    elseif shape.mode == 'polygon' then
    return table.find(shape.vertices, p)
    elseif shape.mode == 'circle' then
    return shape.center == p
    elseif shape.mode == 'arc' then
    return shape.center == p
    -- ugh, how to support angles
    elseif shape.mode == 'deleted' then
    -- already done
    else
    print(shape.mode)
    assert(false)
    end
    end
    function convert_line(drawing, shape)
    -- Perhaps we should do a more sophisticated "simple linear regression"
    -- here:
    -- https://en.wikipedia.org/wiki/Linear_regression#Simple_and_multiple_linear_regression
    -- But this works well enough for close-to-linear strokes.
    assert(shape.mode == 'freehand')
    shape.mode = 'line'
    shape.p1 = insert_point(drawing.points, shape.points[1].x, shape.points[1].y)
    local n = #shape.points
    shape.p2 = insert_point(drawing.points, shape.points[n].x, shape.points[n].y)
    end
    -- turn a line either horizontal or vertical
    function convert_horvert(drawing, shape)
    if shape.mode == 'freehand' then
    convert_line(shape)
    end
    assert(shape.mode == 'line')
    local p1 = drawing.points[shape.p1]
    local p2 = drawing.points[shape.p2]
    if math.abs(p1.x-p2.x) > math.abs(p1.y-p2.y) then
    p2.y = p1.y
    else
    p2.x = p1.x
    end
    end
    function smoothen(shape)
    assert(shape.mode == 'freehand')
    for _=1,7 do
    for i=2,#shape.points-1 do
    local a = shape.points[i-1]
    local b = shape.points[i]
    local c = shape.points[i+1]
    b.x = (a.x + b.x + c.x)/3
    b.y = (a.y + b.y + c.y)/3
  • edit in main.lua at line 505
    [2.417][2.417:431](),[2.431][9.2486:3164](),[9.371][9.2486:3164](),[9.116][9.460:464](),[9.2055][9.460:464](),[9.3164][9.460:464](),[9.460][9.460:464](),[9.464][9.1411:1482](),[9.1482][9.191:226](),[9.226][9.120:155](),[9.155][9.17:57](),[9.57][9.68:104](),[9.104][9.223:276](),[9.223][9.223:276](),[9.276][9.226:246](),[9.226][9.226:246](),[9.281][9.281:298](),[9.298][9.277:402](),[9.402][9.298:316](),[9.298][9.298:316](),[9.316][9.403:441](),[9.441][9.349:492](),[9.349][9.349:492](),[9.492][9.442:503](),[9.503][9.543:554](),[9.543][9.543:554](),[9.554][9.3212:3267](),[9.3267][9.589:613](),[9.589][9.589:613](),[9.613][9.105:128](),[9.128][9.3268:3317](),[9.3317][9.157:163](),[9.157][9.157:163](),[9.163][9.613:747](),[9.613][9.613:747](),[9.747][9.3318:3353](),[9.3353][9.781:825](),[9.781][9.781:825](),[9.825][9.3354:3391]()
    end
    end
    end
    function angle_with_hint(x1, y1, x2, y2, hint)
    local result = math.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 math.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
    function load_from_disk(filename)
    local infile = io.open(filename)
    local result = load_from_file(infile)
    if infile then infile:close() end
    return result
    end
    function load_from_file(infile)
    local result = {}
    if infile then
    local infile_next_line = infile:lines() -- works with both Lua files and LÖVE Files (https://www.love2d.org/wiki/File)
    while true do
    local line = infile_next_line()
    if line == nil then break end
    if line == '```lines' then -- inflexible with whitespace since these files are always autogenerated
    table.insert(result, load_drawing(infile_next_line))
    else
    table.insert(result, {mode='text', data=line})
    end
    end
    end
    if #result == 0 then
    table.insert(result, {mode='text', data=''})
    end
    return result
    end
    function save_to_disk(lines, filename)
    local outfile = io.open(filename, 'w')
    for _,line in ipairs(lines) do
    if line.mode == 'drawing' then
    store_drawing(outfile, line)
    else
    outfile:write(line.data..'\n')
  • edit in main.lua at line 507
    [9.871][9.100:118]()
    outfile:close()
  • edit in main.lua at line 508
    [9.875][9.875:898](),[9.898][9.504:544](),[9.544][9.3392:3470](),[9.3470][9.990:1006](),[9.990][9.990:1006](),[9.1006][9.545:581](),[9.581][9.1037:1126](),[9.1037][9.1037:1126](),[9.1126][3.3:65](),[3.65][9.1159:1299](),[9.1159][9.1159:1299](),[9.1299][3.66:368](),[3.368][9.1299:1489](),[9.1299][9.1299:1489](),[9.1489][9.119:156](),[9.489][9.489:535](),[9.535][3.369:435](),[3.435][9.1522:1630](),[9.572][9.1522:1630](),[9.1522][9.1522:1630](),[9.1630][3.436:700](),[3.700][9.1630:1662](),[9.1630][9.1630:1662](),[9.1662][9.573:612](),[9.612][3.701:1027](),[9.612][9.1662:1701](),[3.1027][9.1662:1701](),[9.1662][9.1662:1701](),[9.1701][9.56:71](),[9.71][6.38:268](),[6.268][9.71:501](),[9.71][9.71:501](),[9.501][9.1701:1705](),[9.1701][9.1701:1705](),[9.1705][9.502:1086](),[9.1086][9.585:674](),[9.750][9.750:775](),[9.775][9.6699:7418](),[9.693][9.1414:1420](),[9.7418][9.1414:1420](),[9.1414][9.1414:1420](),[9.1420][9.7419:7559](),[9.801][9.1546:1552](),[9.7559][9.1546:1552](),[9.1546][9.1546:1552](),[9.1552][9.7560:7725](),[9.929][9.1703:1709](),[9.7725][9.1703:1709](),[9.1703][9.1703:1709](),[9.1709][9.7726:7875](),[9.1044][9.1844:1850](),[9.7875][9.1844:1850](),[9.1844][9.1844:1850](),[9.1850][9.7876:8022](),[9.1155][9.1982:1988](),[9.8022][9.1982:1988](),[9.1982][9.1982:1988](),[9.1988][9.8023:8329](),[9.8329][9.107:146](),[9.1372][9.107:146](),[9.146][9.8330:8434](),[9.245][9.1988:2074](),[9.256][9.1988:2074](),[9.376][9.1988:2074](),[9.1372][9.1988:2074](),[9.8434][9.1988:2074](),[9.1988][9.1988:2074](),[9.2150][9.2150:2175](),[9.2175][9.8435:9016](),[9.9016][9.2699:2744](),[9.2699][9.2699:2744](),[9.2744][9.9017:9231](),[9.2029][9.2938:2947](),[9.9231][9.2938:2947](),[9.2938][9.2938:2947](),[9.2947][9.9232:9332](),[9.756][9.3037:3045](),[9.2129][9.3037:3045](),[9.9332][9.3037:3045](),[9.3037][9.3037:3045](),[9.3045][9.9333:9617](),[9.2373][9.3294:3300](),[9.9617][9.3294:3300](),[9.3294][9.3294:3300](),[9.3300][9.9618:9900](),[9.2624][9.3432:3438](),[9.9900][9.3432:3438](),[9.3432][9.3432:3438](),[9.3438][9.9901:10061](),[9.2747][9.3584:3590](),[9.10061][9.3584:3590](),[9.3584][9.3584:3590](),[9.3590][9.10062:10206](),[9.2857][9.3720:3726](),[9.10206][9.3720:3726](),[9.3720][9.3720:3726](),[9.3726][9.10207:10348](),[9.2963][9.3853:3859](),[9.10348][9.3853:3859](),[9.3853][9.3853:3859](),[9.3859][9.860:899](),[9.899][9.10349:10453](),[9.998][9.3859:3864](),[9.10453][9.3859:3864](),[9.3859][9.3859:3864](),[9.3864][9.999:1029](),[9.1029][9.10454:10491](),[9.10491][9.3935:3964](),[9.3935][9.3935:3964](),[9.3964][9.10492:10529](),[9.10529][9.4001:4028](),[9.4001][9.4001:4028](),[9.4028][9.10530:10572](),[9.10572][9.4070:4108](),[9.4070][9.4070:4108](),[9.4108][9.10573:10644](),[9.10644][9.1101:1118](),[9.1101][9.1101:1118](),[9.1118][9.4108:4115](),[9.4108][9.4108:4115](),[9.4115][9.10645:10669](),[9.10669][9.4139:4150](),[9.4139][9.4139:4150](),[9.4230][9.4230:4445](),[9.4445][9.1086:1090](),[9.1086][9.1086:1090]()
    json = require 'json'
    function load_drawing(infile_next_line)
    local drawing = {mode='drawing', h=256/2, points={}, shapes={}, pending={}}
    while true do
    local line = infile_next_line()
    assert(line)
    if line == '```' then break end
    local shape = json.decode(line)
    if shape.mode == 'line' or shape.mode == 'manhattan' then
    shape.p1 = insert_point(drawing.points, shape.p1.x, shape.p1.y)
    shape.p2 = insert_point(drawing.points, shape.p2.x, shape.p2.y)
    elseif shape.mode == 'polygon' then
    for i,p in ipairs(shape.vertices) do
    shape.vertices[i] = insert_point(drawing.points, p.x,p.y)
    end
    elseif shape.mode == 'circle' or shape.mode == 'arc' then
    shape.center = insert_point(drawing.points, shape.center.x,shape.center.y)
    end
    table.insert(drawing.shapes, shape)
    end
    return drawing
    end
    function store_drawing(outfile, drawing)
    outfile:write('```lines\n')
    for _,shape in ipairs(drawing.shapes) do
    if shape.mode == 'freehand' then
    outfile:write(json.encode(shape)..'\n')
    elseif shape.mode == 'line' or shape.mode == 'manhattan' then
    local line = json.encode({mode=shape.mode, p1=drawing.points[shape.p1], p2=drawing.points[shape.p2]})
    outfile:write(line..'\n')
    elseif shape.mode == 'polygon' then
    local obj = {mode=shape.mode, vertices={}}
    for _,p in ipairs(shape.vertices) do
    table.insert(obj.vertices, drawing.points[p])
    end
    local line = json.encode(obj)
    outfile:write(line..'\n')
    elseif shape.mode == 'circle' then
    outfile:write(json.encode({mode=shape.mode, center=drawing.points[shape.center], radius=shape.radius})..'\n')
    elseif shape.mode == 'arc' then
    outfile:write(json.encode({mode=shape.mode, center=drawing.points[shape.center], radius=shape.radius, start_angle=shape.start_angle, end_angle=shape.end_angle})..'\n')
    end
    end
    outfile:write('```\n')
    end
    icon = {}
    function icon.insert_drawing(x, y)
    love.graphics.setColor(0.7,0.7,0.7)
    love.graphics.rectangle('line', x,y, 12,12)
    love.graphics.line(4,y+6, 16,y+6)
    love.graphics.line(10,y, 10,y+12)
    love.graphics.setColor(0, 0, 0)
    end
    function icon.freehand(x, y)
    love.graphics.line(x+4,y+7,x+5,y+5)
    love.graphics.line(x+5,y+5,x+7,y+4)
    love.graphics.line(x+7,y+4,x+9,y+3)
    love.graphics.line(x+9,y+3,x+10,y+5)
    love.graphics.line(x+10,y+5,x+12,y+6)
    love.graphics.line(x+12,y+6,x+13,y+8)
    love.graphics.line(x+13,y+8,x+13,y+10)
    love.graphics.line(x+13,y+10,x+14,y+12)
    love.graphics.line(x+14,y+12,x+15,y+14)
    love.graphics.line(x+15,y+14,x+15,y+16)
    end
    function icon.line(x, y)
    love.graphics.line(x+4,y+2, x+16,y+18)
    end
    function icon.manhattan(x, y)
    love.graphics.line(x+4,y+20, x+4,y+2)
    love.graphics.line(x+4,y+2, x+10,y+2)
    love.graphics.line(x+10,y+2, x+10,y+10)
    love.graphics.line(x+10,y+10, x+18,y+10)
    end
    function icon.polygon(x, y)
    love.graphics.line(x+8,y+2, x+14,y+2)
    love.graphics.line(x+14,y+2, x+18,y+10)
    love.graphics.line(x+18,y+10, x+10,y+18)
    love.graphics.line(x+10,y+18, x+4,y+12)
    love.graphics.line(x+4,y+12, x+8,y+2)
    end
    function icon.circle(x, y)
    love.graphics.circle('line', x+10,y+10, 8)
    end
    function draw_help_without_mouse_pressed(drawing)
    love.graphics.setColor(0,0.5,0)
    local y = drawing.y+10
    love.graphics.print("Things you can do:", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    love.graphics.print("* Press the mouse button to start drawing a "..current_shape(), 16+30,y, 0, Zoom)
    y = y+15*Zoom
    love.graphics.print("* Hover on a point and press 'ctrl+v' to start moving it,", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    love.graphics.print("then press the mouse button to finish", 16+30+bullet_indent(),y, 0, Zoom)
    y = y+15*Zoom
    love.graphics.print("* Hover on a point or shape and press 'ctrl+d' to delete it", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    y = y+15*Zoom
    if Current_mode ~= 'freehand' then
    love.graphics.print("* Press 'ctrl+f' to switch to drawing freehand strokes", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    end
    if Current_mode ~= 'line' then
    love.graphics.print("* Press 'ctrl+l' to switch to drawing lines", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    end
    if Current_mode ~= 'manhattan' then
    love.graphics.print("* Press 'ctrl+m' to switch to drawing horizontal/vertical lines", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    end
    if Current_mode ~= 'circle' then
    love.graphics.print("* Press 'ctrl+c' to switch to drawing circles/arcs", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    end
    if Current_mode ~= 'polygon' then
    love.graphics.print("* Press 'ctrl+g' to switch to drawing polygons", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    end
    love.graphics.print("* Press 'ctrl+=' or 'ctrl+-' to Zoom in or out", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    love.graphics.print("* Press 'ctrl+0' to reset Zoom", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    y = y+15*Zoom
    love.graphics.print("Hit 'esc' now to hide this message", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    love.graphics.setColor(0,0.5,0, 0.1)
    love.graphics.rectangle('fill', 16,drawing.y, Drawing_width, math.max(pixels(drawing.h),y-drawing.y))
    end
    function draw_help_with_mouse_pressed(drawing)
    love.graphics.setColor(0,0.5,0)
    local y = drawing.y+10
    love.graphics.print("You're currently drawing a "..current_shape(drawing.pending), 16+30,y, 0, Zoom)
    y = y+15*Zoom
    love.graphics.print('Things you can do now:', 16+30,y, 0, Zoom)
    y = y+15*Zoom
    if Current_mode == 'freehand' then
    love.graphics.print('* Release the mouse button to finish drawing the stroke', 16+30,y, 0, Zoom)
    y = y+15*Zoom
    elseif Current_mode == 'line' or Current_mode == 'manhattan' then
    love.graphics.print('* Release the mouse button to finish drawing the line', 16+30,y, 0, Zoom)
    y = y+15*Zoom
    elseif Current_mode == 'circle' then
    if drawing.pending.mode == 'circle' then
    love.graphics.print('* Release the mouse button to finish drawing the circle', 16+30,y, 0, Zoom)
    y = y+15*Zoom
    love.graphics.print("* Press 'a' to draw just an arc of a circle", 16+30,y, 0, Zoom)
    else
    love.graphics.print('* Release the mouse button to finish drawing the arc', 16+30,y, 0, Zoom)
    end
    y = y+15*Zoom
    elseif Current_mode == 'polygon' then
    love.graphics.print('* Release the mouse button to finish drawing the polygon', 16+30,y, 0, Zoom)
    y = y+15*Zoom
    love.graphics.print("* Press 'p' to add a vertex to the polygon", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    end
    love.graphics.print("* Press 'esc' then release the mouse button to cancel the current shape", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    y = y+15*Zoom
    if Current_mode ~= 'line' then
    love.graphics.print("* Press 'l' to switch to drawing lines", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    end
    if Current_mode ~= 'manhattan' then
    love.graphics.print("* Press 'm' to switch to drawing horizontal/vertical lines", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    end
    if Current_mode ~= 'circle' then
    love.graphics.print("* Press 'c' to switch to drawing circles/arcs", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    end
    if Current_mode ~= 'polygon' then
    love.graphics.print("* Press 'g' to switch to drawing polygons", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    end
    love.graphics.setColor(0,0.5,0, 0.1)
    love.graphics.rectangle('fill', 16,drawing.y, Drawing_width, math.max(pixels(drawing.h),y-drawing.y))
    end
    function current_shape(shape)
    if Current_mode == 'freehand' then
    return 'freehand stroke'
    elseif Current_mode == 'line' then
    return 'straight line'
    elseif Current_mode == 'manhattan' then
    return 'horizontal/vertical line'
    elseif Current_mode == 'circle' and shape and shape.start_angle then
    return 'arc'
    else
    return Current_mode
    end
    end
    _bullet_indent = nil
    function bullet_indent()
    if _bullet_indent == nil then
    local text = love.graphics.newText(love.graphics.getFont(), '* ')
    _bullet_indent = text:getWidth()
    end
    return _bullet_indent
    end
  • file addition: icons.lua (----------)
    [85.2]
    icon = {}
    function icon.insert_drawing(x, y)
    love.graphics.setColor(0.7,0.7,0.7)
    love.graphics.rectangle('line', x,y, 12,12)
    love.graphics.line(4,y+6, 16,y+6)
    love.graphics.line(10,y, 10,y+12)
    love.graphics.setColor(0, 0, 0)
    end
    function icon.freehand(x, y)
    love.graphics.line(x+4,y+7,x+5,y+5)
    love.graphics.line(x+5,y+5,x+7,y+4)
    love.graphics.line(x+7,y+4,x+9,y+3)
    love.graphics.line(x+9,y+3,x+10,y+5)
    love.graphics.line(x+10,y+5,x+12,y+6)
    love.graphics.line(x+12,y+6,x+13,y+8)
    love.graphics.line(x+13,y+8,x+13,y+10)
    love.graphics.line(x+13,y+10,x+14,y+12)
    love.graphics.line(x+14,y+12,x+15,y+14)
    love.graphics.line(x+15,y+14,x+15,y+16)
    end
    function icon.line(x, y)
    love.graphics.line(x+4,y+2, x+16,y+18)
    end
    function icon.manhattan(x, y)
    love.graphics.line(x+4,y+20, x+4,y+2)
    love.graphics.line(x+4,y+2, x+10,y+2)
    love.graphics.line(x+10,y+2, x+10,y+10)
    love.graphics.line(x+10,y+10, x+18,y+10)
    end
    function icon.polygon(x, y)
    love.graphics.line(x+8,y+2, x+14,y+2)
    love.graphics.line(x+14,y+2, x+18,y+10)
    love.graphics.line(x+18,y+10, x+10,y+18)
    love.graphics.line(x+10,y+18, x+4,y+12)
    love.graphics.line(x+4,y+12, x+8,y+2)
    end
    function icon.circle(x, y)
    love.graphics.circle('line', x+10,y+10, 8)
    end
  • file addition: help.lua (----------)
    [85.2]
    function draw_help_without_mouse_pressed(drawing)
    love.graphics.setColor(0,0.5,0)
    local y = drawing.y+10
    love.graphics.print("Things you can do:", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    love.graphics.print("* Press the mouse button to start drawing a "..current_shape(), 16+30,y, 0, Zoom)
    y = y+15*Zoom
    love.graphics.print("* Hover on a point and press 'ctrl+v' to start moving it,", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    love.graphics.print("then press the mouse button to finish", 16+30+bullet_indent(),y, 0, Zoom)
    y = y+15*Zoom
    love.graphics.print("* Hover on a point or shape and press 'ctrl+d' to delete it", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    y = y+15*Zoom
    if Current_drawing_mode ~= 'freehand' then
    love.graphics.print("* Press 'ctrl+f' to switch to drawing freehand strokes", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    end
    if Current_drawing_mode ~= 'line' then
    love.graphics.print("* Press 'ctrl+l' to switch to drawing lines", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    end
    if Current_drawing_mode ~= 'manhattan' then
    love.graphics.print("* Press 'ctrl+m' to switch to drawing horizontal/vertical lines", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    end
    if Current_drawing_mode ~= 'circle' then
    love.graphics.print("* Press 'ctrl+c' to switch to drawing circles/arcs", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    end
    if Current_drawing_mode ~= 'polygon' then
    love.graphics.print("* Press 'ctrl+g' to switch to drawing polygons", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    end
    love.graphics.print("* Press 'ctrl+=' or 'ctrl+-' to Zoom in or out", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    love.graphics.print("* Press 'ctrl+0' to reset Zoom", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    y = y+15*Zoom
    love.graphics.print("Hit 'esc' now to hide this message", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    love.graphics.setColor(0,0.5,0, 0.1)
    love.graphics.rectangle('fill', 16,drawing.y, Drawing_width, math.max(Drawing.pixels(drawing.h),y-drawing.y))
    end
    function draw_help_with_mouse_pressed(drawing)
    love.graphics.setColor(0,0.5,0)
    local y = drawing.y+10
    love.graphics.print("You're currently drawing a "..current_shape(drawing.pending), 16+30,y, 0, Zoom)
    y = y+15*Zoom
    love.graphics.print('Things you can do now:', 16+30,y, 0, Zoom)
    y = y+15*Zoom
    if Current_drawing_mode == 'freehand' then
    love.graphics.print('* Release the mouse button to finish drawing the stroke', 16+30,y, 0, Zoom)
    y = y+15*Zoom
    elseif Current_drawing_mode == 'line' or Current_drawing_mode == 'manhattan' then
    love.graphics.print('* Release the mouse button to finish drawing the line', 16+30,y, 0, Zoom)
    y = y+15*Zoom
    elseif Current_drawing_mode == 'circle' then
    if drawing.pending.mode == 'circle' then
    love.graphics.print('* Release the mouse button to finish drawing the circle', 16+30,y, 0, Zoom)
    y = y+15*Zoom
    love.graphics.print("* Press 'a' to draw just an arc of a circle", 16+30,y, 0, Zoom)
    else
    love.graphics.print('* Release the mouse button to finish drawing the arc', 16+30,y, 0, Zoom)
    end
    y = y+15*Zoom
    elseif Current_drawing_mode == 'polygon' then
    love.graphics.print('* Release the mouse button to finish drawing the polygon', 16+30,y, 0, Zoom)
    y = y+15*Zoom
    love.graphics.print("* Press 'p' to add a vertex to the polygon", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    end
    love.graphics.print("* Press 'esc' then release the mouse button to cancel the current shape", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    y = y+15*Zoom
    if Current_drawing_mode ~= 'line' then
    love.graphics.print("* Press 'l' to switch to drawing lines", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    end
    if Current_drawing_mode ~= 'manhattan' then
    love.graphics.print("* Press 'm' to switch to drawing horizontal/vertical lines", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    end
    if Current_drawing_mode ~= 'circle' then
    love.graphics.print("* Press 'c' to switch to drawing circles/arcs", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    end
    if Current_drawing_mode ~= 'polygon' then
    love.graphics.print("* Press 'g' to switch to drawing polygons", 16+30,y, 0, Zoom)
    y = y+15*Zoom
    end
    love.graphics.setColor(0,0.5,0, 0.1)
    love.graphics.rectangle('fill', 16,drawing.y, Drawing_width, math.max(Drawing.pixels(drawing.h),y-drawing.y))
    end
    function current_shape(shape)
    if Current_drawing_mode == 'freehand' then
    return 'freehand stroke'
    elseif Current_drawing_mode == 'line' then
    return 'straight line'
    elseif Current_drawing_mode == 'manhattan' then
    return 'horizontal/vertical line'
    elseif Current_drawing_mode == 'circle' and shape and shape.start_angle then
    return 'arc'
    else
    return Current_drawing_mode
    end
    end
    _bullet_indent = nil
    function bullet_indent()
    if _bullet_indent == nil then
    local text = love.graphics.newText(love.graphics.getFont(), '* ')
    _bullet_indent = text:getWidth()
    end
    return _bullet_indent
    end
  • file addition: geom.lua (----------)
    [85.2]
    local geom = {}
    function geom.on_shape(x,y, drawing, shape)
    if shape.mode == 'freehand' then
    return geom.on_freehand(x,y, drawing, shape)
    elseif shape.mode == 'line' then
    return geom.on_line(x,y, drawing, shape)
    elseif shape.mode == 'manhattan' then
    return x == drawing.points[shape.p1].x or y == drawing.points[shape.p1].y
    elseif shape.mode == 'polygon' then
    return geom.on_polygon(x,y, drawing, shape)
    elseif shape.mode == 'circle' then
    local center = drawing.points[shape.center]
    return math.dist(center.x,center.y, x,y) == shape.radius
    elseif shape.mode == 'arc' then
    local center = drawing.points[shape.center]
    local dist = math.dist(center.x,center.y, x,y)
    if dist < shape.radius*0.95 or dist > shape.radius*1.05 then
    return false
    end
    return geom.angle_between(center.x,center.y, x,y, shape.start_angle,shape.end_angle)
    elseif shape.mode == 'deleted' then
    else
    print(shape.mode)
    assert(false)
    end
    end
    function geom.on_freehand(x,y, drawing, shape)
    local prev
    for _,p in ipairs(shape.points) do
    if prev then
    if geom.on_line(x,y, drawing, {p1=prev, p2=p}) then
    return true
    end
    end
    prev = p
    end
    return false
    end
    function geom.on_line(x,y, drawing, shape)
    local p1,p2
    if type(shape.p1) == 'number' then
    p1 = drawing.points[shape.p1]
    p2 = drawing.points[shape.p2]
    else
    p1 = shape.p1
    p2 = shape.p2
    end
    if p1.x == p2.x then
    if math.abs(p1.x-x) > 5 then
    return false
    end
    local y1,y2 = p1.y,p2.y
    if y1 > y2 then
    y1,y2 = y2,y1
    end
    return y >= y1 and y <= y2
    end
    -- has the right slope and intercept
    local m = (p2.y - p1.y) / (p2.x - p1.x)
    local yp = p1.y + m*(x-p1.x)
    if yp < 0.95*y or yp > 1.05*y then
    return false
    end
    -- between endpoints
    local k = (x-p1.x) / (p2.x-p1.x)
    return k > -0.05 and k < 1.05
    end
    function geom.on_polygon(x,y, drawing, shape)
    local prev
    for _,p in ipairs(shape.vertices) do
    if prev then
    if geom.on_line(x,y, drawing, {p1=prev, p2=p}) then
    return true
    end
    end
    prev = p
    end
    return geom.on_line(x,y, drawing, {p1=shape.vertices[1], p2=shape.vertices[#shape.vertices]})
    end
    function geom.angle_with_hint(x1, y1, x2, y2, hint)
    local result = geom.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 geom.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
    -- is the line between x,y and cx,cy at an angle between s and e?
    function geom.angle_between(ox,oy, x,y, s,e)
    local angle = math.angle(ox,oy, x,y)
    if s > e then
    s,e = e,s
    end
    -- I'm not sure this is right or ideal..
    angle = angle-math.pi*2
    if s <= angle and angle <= e then
    return true
    end
    angle = angle+math.pi*2
    if s <= angle and angle <= e then
    return true
    end
    angle = angle+math.pi*2
    return s <= angle and angle <= e
    end
    function geom.dist(x1,y1, x2,y2) return ((x2-x1)^2+(y2-y1)^2)^0.5 end
    return geom
  • file addition: file.lua (----------)
    [85.2]
    -- primitives for saving to file and loading from file
    Drawing = require 'drawing'
    function load_from_disk(filename)
    local infile = io.open(filename)
    local result = load_from_file(infile)
    if infile then infile:close() end
    return result
    end
    function load_from_file(infile)
    local result = {}
    if infile then
    local infile_next_line = infile:lines() -- works with both Lua files and LÖVE Files (https://www.love2d.org/wiki/File)
    while true do
    local line = infile_next_line()
    if line == nil then break end
    if line == '```lines' then -- inflexible with whitespace since these files are always autogenerated
    table.insert(result, load_drawing(infile_next_line))
    else
    table.insert(result, {mode='text', data=line})
    end
    end
    end
    if #result == 0 then
    table.insert(result, {mode='text', data=''})
    end
    return result
    end
    function save_to_disk(lines, filename)
    local outfile = io.open(filename, 'w')
    for _,line in ipairs(lines) do
    if line.mode == 'drawing' then
    store_drawing(outfile, line)
    else
    outfile:write(line.data..'\n')
    end
    end
    outfile:close()
    end
    json = require 'json'
    function load_drawing(infile_next_line)
    local drawing = {mode='drawing', h=256/2, points={}, shapes={}, pending={}}
    while true do
    local line = infile_next_line()
    assert(line)
    if line == '```' then break end
    local shape = json.decode(line)
    if shape.mode == 'line' or shape.mode == 'manhattan' then
    shape.p1 = Drawing.insert_point(drawing.points, shape.p1.x, shape.p1.y)
    shape.p2 = Drawing.insert_point(drawing.points, shape.p2.x, shape.p2.y)
    elseif shape.mode == 'polygon' then
    for i,p in ipairs(shape.vertices) do
    shape.vertices[i] = Drawing.insert_point(drawing.points, p.x,p.y)
    end
    elseif shape.mode == 'circle' or shape.mode == 'arc' then
    shape.center = Drawing.insert_point(drawing.points, shape.center.x,shape.center.y)
    end
    table.insert(drawing.shapes, shape)
    end
    return drawing
    end
    function store_drawing(outfile, drawing)
    outfile:write('```lines\n')
    for _,shape in ipairs(drawing.shapes) do
    if shape.mode == 'freehand' then
    outfile:write(json.encode(shape)..'\n')
    elseif shape.mode == 'line' or shape.mode == 'manhattan' then
    local line = json.encode({mode=shape.mode, p1=drawing.points[shape.p1], p2=drawing.points[shape.p2]})
    outfile:write(line..'\n')
    elseif shape.mode == 'polygon' then
    local obj = {mode=shape.mode, vertices={}}
    for _,p in ipairs(shape.vertices) do
    table.insert(obj.vertices, drawing.points[p])
    end
    local line = json.encode(obj)
    outfile:write(line..'\n')
    elseif shape.mode == 'circle' then
    outfile:write(json.encode({mode=shape.mode, center=drawing.points[shape.center], radius=shape.radius})..'\n')
    elseif shape.mode == 'arc' then
    outfile:write(json.encode({mode=shape.mode, center=drawing.points[shape.center], radius=shape.radius, start_angle=shape.start_angle, end_angle=shape.end_angle})..'\n')
    end
    end
    outfile:write('```\n')
    end
  • edit in drawing.lua at line 3
    [7.147]
    [7.147]
    geom = require 'geom'
  • replacement in drawing.lua at line 7
    [7.234][7.234:316]()
    if pmx < 16+Drawing_width and pmy > line.y and pmy < line.y+pixels(line.h) then
    [7.234]
    [7.316]
    if pmx < 16+Drawing_width and pmy > line.y and pmy < line.y+Drawing.pixels(line.h) then
  • replacement in drawing.lua at line 9
    [7.359][7.359:523]()
    love.graphics.rectangle('line', 16,line.y, Drawing_width,pixels(line.h))
    if icon[Current_mode] then
    icon[Current_mode](16+Drawing_width-20, line.y+4)
    [7.359]
    [7.523]
    love.graphics.rectangle('line', 16,line.y, Drawing_width,Drawing.pixels(line.h))
    if icon[Current_drawing_mode] then
    icon[Current_drawing_mode](16+Drawing_width-20, line.y+4)
  • replacement in drawing.lua at line 13
    [7.532][7.532:589]()
    icon[Previous_mode](16+Drawing_width-20, line.y+4)
    [7.532]
    [7.589]
    icon[Previous_drawing_mode](16+Drawing_width-20, line.y+4)
  • replacement in drawing.lua at line 27
    [7.817][7.817:894]()
    local mx,my = coord(love.mouse.getX()-16), coord(love.mouse.getY()-line.y)
    [7.817]
    [7.894]
    local mx,my = Drawing.coord(love.mouse.getX()-16), Drawing.coord(love.mouse.getY()-line.y)
  • replacement in drawing.lua at line 31
    [7.953][7.953:994]()
    if on_shape(mx,my, line, shape) then
    [7.953]
    [7.994]
    if geom.on_shape(mx,my, line, shape) then
  • replacement in drawing.lua at line 36
    [7.1083][7.1083:1122]()
    draw_shape(16,line.y, line, shape)
    [7.1083]
    [7.1122]
    Drawing.draw_shape(16,line.y, line, shape)
  • replacement in drawing.lua at line 40
    [7.1193][7.1193:1222]()
    if near(p, mx,my) then
    [7.1193]
    [7.1222]
    if Drawing.near(p, mx,my) then
  • replacement in drawing.lua at line 42
    [7.1260][7.1260:1335]()
    love.graphics.circle('line', pixels(p.x)+16,pixels(p.y)+line.y, 4)
    [7.1260]
    [7.1335]
    love.graphics.circle('line', Drawing.pixels(p.x)+16,Drawing.pixels(p.y)+line.y, 4)
  • replacement in drawing.lua at line 45
    [7.1384][7.1384:1459]()
    love.graphics.circle('fill', pixels(p.x)+16,pixels(p.y)+line.y, 2)
    [7.1384]
    [7.1459]
    love.graphics.circle('fill', Drawing.pixels(p.x)+16,Drawing.pixels(p.y)+line.y, 2)
  • replacement in drawing.lua at line 49
    [7.1483][7.1483:1521]()
    draw_pending_shape(16,line.y, line)
    [7.1483]
    [7.1521]
    Drawing.draw_pending_shape(16,line.y, line)
    end
    function Drawing.current_drawing()
    local x, y = love.mouse.getX(), love.mouse.getY()
    for _,drawing in ipairs(Lines) do
    if drawing.mode == 'drawing' then
    if y >= drawing.y and y < drawing.y + Drawing.pixels(drawing.h) and x >= 16 and x < 16+Drawing_width then
    return drawing
    end
    end
    end
    return nil
    end
    function Drawing.select_shape_at_mouse()
    for _,drawing in ipairs(Lines) do
    if drawing.mode == 'drawing' then
    local x, y = love.mouse.getX(), love.mouse.getY()
    if y >= drawing.y and y < drawing.y + Drawing.pixels(drawing.h) and x >= 16 and x < 16+Drawing_width then
    local mx,my = Drawing.coord(love.mouse.getX()-16), Drawing.coord(love.mouse.getY()-drawing.y)
    for i,shape in ipairs(drawing.shapes) do
    assert(shape)
    if geom.on_shape(mx,my, drawing, shape) then
    return drawing,i,shape
    end
    end
    end
    end
    end
    end
    function Drawing.select_point_at_mouse()
    for _,drawing in ipairs(Lines) do
    if drawing.mode == 'drawing' then
    local x, y = love.mouse.getX(), love.mouse.getY()
    if y >= drawing.y and y < drawing.y + Drawing.pixels(drawing.h) and x >= 16 and x < 16+Drawing_width then
    local mx,my = Drawing.coord(love.mouse.getX()-16), Drawing.coord(love.mouse.getY()-drawing.y)
    for i,point in ipairs(drawing.points) do
    assert(point)
    if Drawing.near(point, mx,my) then
    return drawing,i,point
    end
    end
    end
    end
    end
    end
    function Drawing.select_drawing_at_mouse()
    for _,drawing in ipairs(Lines) do
    if drawing.mode == 'drawing' then
    local x, y = love.mouse.getX(), love.mouse.getY()
    if y >= drawing.y and y < drawing.y + Drawing.pixels(drawing.h) and x >= 16 and x < 16+Drawing_width then
    return drawing
    end
    end
    end
    end
    function Drawing.contains_point(shape, p)
    if shape.mode == 'freehand' then
    -- not supported
    elseif shape.mode == 'line' or shape.mode == 'manhattan' then
    return shape.p1 == p or shape.p2 == p
    elseif shape.mode == 'polygon' then
    return table.find(shape.vertices, p)
    elseif shape.mode == 'circle' then
    return shape.center == p
    elseif shape.mode == 'arc' then
    return shape.center == p
    -- ugh, how to support angles
    elseif shape.mode == 'deleted' then
    -- already done
    else
    print(shape.mode)
    assert(false)
    end
    end
    function Drawing.convert_line(drawing, shape)
    -- Perhaps we should do a more sophisticated "simple linear regression"
    -- here:
    -- https://en.wikipedia.org/wiki/Linear_regression#Simple_and_multiple_linear_regression
    -- But this works well enough for close-to-linear strokes.
    assert(shape.mode == 'freehand')
    shape.mode = 'line'
    shape.p1 = insert_point(drawing.points, shape.points[1].x, shape.points[1].y)
    local n = #shape.points
    shape.p2 = insert_point(drawing.points, shape.points[n].x, shape.points[n].y)
    end
    -- turn a line either horizontal or vertical
    function Drawing.convert_horvert(drawing, shape)
    if shape.mode == 'freehand' then
    convert_line(shape)
    end
    assert(shape.mode == 'line')
    local p1 = drawing.points[shape.p1]
    local p2 = drawing.points[shape.p2]
    if math.abs(p1.x-p2.x) > math.abs(p1.y-p2.y) then
    p2.y = p1.y
    else
    p2.x = p1.x
    end
    end
    function Drawing.smoothen(shape)
    assert(shape.mode == 'freehand')
    for _=1,7 do
    for i=2,#shape.points-1 do
    local a = shape.points[i-1]
    local b = shape.points[i]
    local c = shape.points[i+1]
    b.x = (a.x + b.x + c.x)/3
    b.y = (a.y + b.y + c.y)/3
    end
    end
    end
    function Drawing.insert_point(points, x,y)
    for i,point in ipairs(points) do
    if Drawing.near(point, x,y) then
    return i
    end
    end
    table.insert(points, {x=x, y=y})
    return #points
    end
    function Drawing.near(point, x,y)
    local px,py = Drawing.pixels(x),Drawing.pixels(y)
    local cx,cy = Drawing.pixels(point.x), Drawing.pixels(point.y)
    return (cx-px)*(cx-px) + (cy-py)*(cy-py) < 16
    end
    function Drawing.draw_shape(left,top, drawing, shape)
    if shape.mode == 'freehand' then
    local prev = nil
    for _,point in ipairs(shape.points) do
    if prev then
    love.graphics.line(Drawing.pixels(prev.x)+left,Drawing.pixels(prev.y)+top, Drawing.pixels(point.x)+left,Drawing.pixels(point.y)+top)
    end
    prev = point
    end
    elseif shape.mode == 'line' or shape.mode == 'manhattan' then
    local p1 = drawing.points[shape.p1]
    local p2 = drawing.points[shape.p2]
    love.graphics.line(Drawing.pixels(p1.x)+left,Drawing.pixels(p1.y)+top, Drawing.pixels(p2.x)+left,Drawing.pixels(p2.y)+top)
    elseif shape.mode == 'polygon' then
    local prev = nil
    for _,point in ipairs(shape.vertices) do
    local curr = drawing.points[point]
    if prev then
    love.graphics.line(Drawing.pixels(prev.x)+left,Drawing.pixels(prev.y)+top, Drawing.pixels(curr.x)+left,Drawing.pixels(curr.y)+top)
    end
    prev = curr
    end
    -- close the loop
    local curr = drawing.points[shape.vertices[1]]
    love.graphics.line(Drawing.pixels(prev.x)+left,Drawing.pixels(prev.y)+top, Drawing.pixels(curr.x)+left,Drawing.pixels(curr.y)+top)
    elseif shape.mode == 'circle' then
    local center = drawing.points[shape.center]
    love.graphics.circle('line', Drawing.pixels(center.x)+left,Drawing.pixels(center.y)+top, Drawing.pixels(shape.radius))
    elseif shape.mode == 'arc' then
    local center = drawing.points[shape.center]
    love.graphics.arc('line', 'open', Drawing.pixels(center.x)+left,Drawing.pixels(center.y)+top, Drawing.pixels(shape.radius), shape.start_angle, shape.end_angle, 360)
    elseif shape.mode == 'deleted' then
    else
    print(shape.mode)
    assert(false)
    end
    end
    function Drawing.draw_pending_shape(left,top, drawing)
    local shape = drawing.pending
    if shape.mode == 'freehand' then
    draw_shape(left,top, drawing, shape)
    elseif shape.mode == 'line' then
    local p1 = drawing.points[shape.p1]
    local mx,my = Drawing.coord(love.mouse.getX()-16), Drawing.coord(love.mouse.getY()-drawing.y)
    if mx < 0 or mx >= 256 or my < 0 or my >= drawing.h then
    return
    end
    love.graphics.line(Drawing.pixels(p1.x)+left,Drawing.pixels(p1.y)+top, Drawing.pixels(mx)+left,Drawing.pixels(my)+top)
    elseif shape.mode == 'manhattan' then
    local p1 = drawing.points[shape.p1]
    local mx,my = Drawing.coord(love.mouse.getX()-16), Drawing.coord(love.mouse.getY()-drawing.y)
    if mx < 0 or mx >= 256 or my < 0 or my >= drawing.h then
    return
    end
    if math.abs(mx-p1.x) > math.abs(my-p1.y) then
    love.graphics.line(Drawing.pixels(p1.x)+left,Drawing.pixels(p1.y)+top, Drawing.pixels(mx)+left,Drawing.pixels(p1.y)+top)
    else
    love.graphics.line(Drawing.pixels(p1.x)+left,Drawing.pixels(p1.y)+top, Drawing.pixels(p1.x)+left,Drawing.pixels(my)+top)
    end
    elseif shape.mode == 'polygon' then
    -- don't close the loop on a pending polygon
    local prev = nil
    for _,point in ipairs(shape.vertices) do
    local curr = drawing.points[point]
    if prev then
    love.graphics.line(Drawing.pixels(prev.x)+left,Drawing.pixels(prev.y)+top, Drawing.pixels(curr.x)+left,Drawing.pixels(curr.y)+top)
    end
    prev = curr
    end
    love.graphics.line(Drawing.pixels(prev.x)+left,Drawing.pixels(prev.y)+top, love.mouse.getX(),love.mouse.getY())
    elseif shape.mode == 'circle' then
    local center = drawing.points[shape.center]
    local mx,my = Drawing.coord(love.mouse.getX()-16), Drawing.coord(love.mouse.getY()-drawing.y)
    if mx < 0 or mx >= 256 or my < 0 or my >= drawing.h then
    return
    end
    local cx,cy = Drawing.pixels(center.x)+left, Drawing.pixels(center.y)+top
    love.graphics.circle('line', cx,cy, math.dist(cx,cy, love.mouse.getX(),love.mouse.getY()))
    elseif shape.mode == 'arc' then
    local center = drawing.points[shape.center]
    local mx,my = Drawing.coord(love.mouse.getX()-16), Drawing.coord(love.mouse.getY()-drawing.y)
    if mx < 0 or mx >= 256 or my < 0 or my >= drawing.h then
    return
    end
    shape.end_angle = geom.angle_with_hint(center.x,center.y, mx,my, shape.end_angle)
    local cx,cy = Drawing.pixels(center.x)+left, Drawing.pixels(center.y)+top
    love.graphics.arc('line', 'open', cx,cy, Drawing.pixels(shape.radius), shape.start_angle, shape.end_angle, 360)
    end
    end
    function Drawing.pixels(n) -- parts to pixels
    return n*Drawing_width/256
    end
    function Drawing.coord(n) -- pixels to parts
    return math.floor(n*256/Drawing_width)