about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2022-05-14 16:00:21 -0700
committerKartik K. Agaram <vc@akkartik.com>2022-05-14 16:00:21 -0700
commit7d5a70379f5d2face8dcafb9d4816fff3c60599b (patch)
treeb3ba993aee8b82183d9f2fd52b19b774c08727b2
parentece73b6683fb71248a9055dc1d5fbff565bdf5bc (diff)
downloadlines.love-7d5a70379f5d2face8dcafb9d4816fff3c60599b.tar.gz
add a level of indirection to vertices of shapes
This is like Sketchpad.
-rw-r--r--main.lua105
1 files changed, 68 insertions, 37 deletions
diff --git a/main.lua b/main.lua
index d0bb18c..8b8f90b 100644
--- a/main.lua
+++ b/main.lua
@@ -75,7 +75,7 @@ function love.draw()
                  love.graphics.setColor(0, 0, 0)
                end,
         onpress1 = function()
-                     table.insert(lines, i, {y=y, h=256/2, shapes={}, pending={}})
+                     table.insert(lines, i, {y=y, h=256/2, points={}, shapes={}, pending={}})
                    end})
     elseif type(line) == 'table' then
       -- line drawing
@@ -87,14 +87,22 @@ function love.draw()
       local mx,my = coord(love.mouse.getX()-16), coord(love.mouse.getY()-line.y)
 
       for _,shape in ipairs(line.shapes) do
-        if on_shape(mx,my, shape) then
+        if on_shape(mx,my, line, shape) then
           love.graphics.setColor(1,0,0)
         else
           love.graphics.setColor(0,0,0)
         end
-        draw_shape(16,line.y, shape)
+        draw_shape(16,line.y, line, shape)
       end
-      draw_pending_shape(16,line.y, line.pending)
+      for _,p in ipairs(line.points) do
+        if p.x == mx and p.y == my then
+          love.graphics.setColor(1,0,0)
+        else
+          love.graphics.setColor(0,0,0)
+        end
+        love.graphics.circle('line', pixels(p.x)+16,pixels(p.y)+line.y, 4)
+      end
+      draw_pending_shape(16,line.y, line)
     else
       love.graphics.draw(text, 25,y, 0, 1.5)
     end
@@ -135,8 +143,8 @@ function love.mousereleased(x,y, button)
       if lines.current.pending.mode == 'freehand' then
         -- the last point added during update is good enough
       elseif lines.current.pending.mode == 'line' then
-        lines.current.pending.x2 = coord(x-16)
-        lines.current.pending.y2 = coord(y-lines.current.y)
+        local j = insert_point(lines.current.points, coord(x-16), coord(y-lines.current.y))
+        lines.current.pending.p2 = j
       end
       table.insert(lines.current.shapes, lines.current.pending)
       lines.current.pending = {}
@@ -153,7 +161,8 @@ function propagate_to_drawings(x,y, button)
         if current_mode == 'freehand' then
           drawing.pending = {mode='freehand', points={x=coord(x-16), y=coord(y-drawing.y)}}
         elseif current_mode == 'line' then
-          drawing.pending = {mode='line', x1=coord(x-16), y1=coord(y-drawing.y)}
+          local j = insert_point(drawing.points, coord(x-16), coord(y-drawing.y))
+          drawing.pending = {mode='line', p1=j}
         end
         lines.current = drawing
       end
@@ -161,7 +170,17 @@ function propagate_to_drawings(x,y, button)
   end
 end
 
-function draw_shape(left,top, shape)
+function insert_point(points, x,y)
+  for i,point in ipairs(points) do
+    if point.x == x and point.y == y then
+      return i
+    end
+  end
+  table.insert(points, {x=x, y=y})
+  return #points
+end
+
+function draw_shape(left,top, drawing, shape)
   if shape.mode == 'freehand' then
     local prev = nil
     for _,point in ipairs(shape.points) do
@@ -171,33 +190,37 @@ function draw_shape(left,top, shape)
       prev = point
     end
   elseif shape.mode == 'line' then
-    love.graphics.line(pixels(shape.x1)+left,pixels(shape.y1)+top, pixels(shape.x2)+left,pixels(shape.y2)+top)
+    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)
   end
 end
 
-function draw_pending_shape(left,top, shape)
+function draw_pending_shape(left,top, drawing)
+  local shape = drawing.pending
   if shape.mode == 'freehand' then
-    draw_shape(left,top, shape)
+    draw_shape(left,top, drawing, shape)
   elseif shape.mode == 'line' then
-    love.graphics.line(pixels(shape.x1)+left,pixels(shape.y1)+top, love.mouse.getX(),love.mouse.getY())
+    local p1 = drawing.points[shape.p1]
+    love.graphics.line(pixels(p1.x)+left,pixels(p1.y)+top, love.mouse.getX(),love.mouse.getY())
   end
 end
 
-function on_shape(x,y, shape)
+function on_shape(x,y, drawing, shape)
   if shape.mode == 'freehand' then
-    return on_freehand(x,y, shape)
+    return on_freehand(x,y, drawing, shape)
   elseif shape.mode == 'line' then
-    return on_line(x,y, shape)
+    return on_line(x,y, drawing, shape)
   else
     assert(false)
   end
 end
 
-function on_freehand(x,y, shape)
+function on_freehand(x,y, drawing, shape)
   local prev
   for _,p in ipairs(shape.points) do
     if prev then
-      if on_line(x,y, {x1=prev.x,y1=prev.y, x2=p.x,y2=p.y}) then
+      if on_line(x,y, drawing, {p1=prev, p2=p}) then
         return true
       end
     end
@@ -206,25 +229,33 @@ function on_freehand(x,y, shape)
   return false
 end
 
-function on_line(x,y, shape)
-  if shape.x1 == shape.x2 then
-    if math.abs(shape.x1-x) > 5 then
+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 = shape.y1,shape.y2
+    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 = (shape.y2 - shape.y1) / (shape.x2 - shape.x1)
-  local yp = shape.y1 + m*(x-shape.x1)
+  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-shape.x1) / (shape.x2-shape.x1)
+  local k = (x-p1.x) / (p2.x-p1.x)
   return k > -0.05 and k < 1.05
 end
 
@@ -259,18 +290,17 @@ function keychord_pressed(chord)
     local drawing = current_drawing()
     assert(drawing.pending.mode == 'freehand')
     drawing.pending.mode = 'line'
-    drawing.pending.x1 = drawing.pending.points[1].x
-    drawing.pending.y1 = drawing.pending.points[1].y
+    drawing.pending.p1 = insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)
   elseif chord == 'C-l' then
     current_mode = 'line'
     local drawing,i,shape = select_shape_at_mouse()
     if drawing then
-      convert_line(shape)
+      convert_line(drawing, shape)
     end
   elseif chord == 'C-m' then
     local drawing,i,shape = select_shape_at_mouse()
     if drawing then
-      convert_horvert(shape)
+      convert_horvert(drawing, shape)
     end
   elseif chord == 'C-s' then
     local drawing,i,shape = select_shape_at_mouse()
@@ -320,29 +350,30 @@ function select_shape_at_mouse()
   end
 end
 
-function convert_line(shape)
+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.x1 = shape.points[1].x
-  shape.y1 = shape.points[1].y
-  shape.x2 = shape.points[#shape.points].x
-  shape.y2 = shape.points[#shape.points].y
+  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(shape)
+function convert_horvert(drawing, shape)
   if shape.mode == 'freehand' then
     convert_line(shape)
   end
   assert(shape.mode == 'line')
-  if math.abs(shape.x1-shape.x2) > math.abs(shape.y1-shape.y2) then
-    shape.y2 = shape.y1
+  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
-    shape.x2 = shape.x1
+    p2.x = p1.x
   end
 end
 
=4c13e1f2d85483e026d79ab05da9f1e8e4b45293'>4c13e1f2 ^
f07bb12f ^


62cd83ba ^

f07bb12f ^




4c13e1f2 ^
f07bb12f ^
4c13e1f2 ^

f07bb12f ^



f07bb12f ^















4c13e1f2 ^




34a60763 ^
4c13e1f2 ^
34a60763 ^
4c13e1f2 ^



f07bb12f ^
62cd83ba ^
f07bb12f ^
c776804d ^






c9383c72 ^

f07bb12f ^
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179