3 function geom
.on_shape(x
,y
, drawing
, shape
)
4 if shape
.mode
== 'freehand' then
5 return geom
.on_freehand(x
,y
, drawing
, shape
)
6 elseif shape
.mode
== 'line' then
7 return geom
.on_line(x
,y
, drawing
, shape
)
8 elseif shape
.mode
== 'manhattan' then
9 local p1
= drawing
.points
[shape
.p1
]
10 local p2
= drawing
.points
[shape
.p2
]
12 if x
~= p1
.x
then return false end
13 local y1
,y2
= p1
.y
, p2
.y
17 return y
>= y1
-2 and y
<= y2
+2
18 elseif p1
.y
== p2
.y
then
19 if y
~= p1
.y
then return false end
20 local x1
,x2
= p1
.x
, p2
.x
24 return x
>= x1
-2 and x
<= x2
+2
26 elseif shape
.mode
== 'polygon' or shape
.mode
== 'rectangle' or shape
.mode
== 'square' then
27 return geom
.on_polygon(x
,y
, drawing
, shape
)
28 elseif shape
.mode
== 'circle' then
29 local center
= drawing
.points
[shape
.center
]
30 local dist
= geom
.dist(center
.x
,center
.y
, x
,y
)
31 return dist
> shape
.radius
*0.95 and dist
< shape
.radius
*1.05
32 elseif shape
.mode
== 'arc' then
33 local center
= drawing
.points
[shape
.center
]
34 local dist
= geom
.dist(center
.x
,center
.y
, x
,y
)
35 if dist
< shape
.radius
*0.95 or dist
> shape
.radius
*1.05 then
38 return geom
.angle_between(center
.x
,center
.y
, x
,y
, shape
.start_angle
,shape
.end_angle
)
39 elseif shape
.mode
== 'deleted' then
41 assert(false, ('unknown drawing mode %s'):format(shape
.mode
))
45 function geom
.on_freehand(x
,y
, drawing
, shape
)
47 for _
,p
in ipairs(shape
.points
) do
49 if geom
.on_line(x
,y
, drawing
, {p1
=prev
, p2
=p
}) then
58 function geom
.on_line(x
,y
, drawing
, shape
)
60 if type(shape
.p1
) == 'number' then
61 p1
= drawing
.points
[shape
.p1
]
62 p2
= drawing
.points
[shape
.p2
]
68 if math
.abs(p1
.x
-x
) > 2 then
71 local y1
,y2
= p1
.y
,p2
.y
75 return y
>= y1
-2 and y
<= y2
+2
77 -- has the right slope and intercept
78 local m
= (p2
.y
- p1
.y
) / (p2
.x
- p1
.x
)
79 local yp
= p1
.y
+ m
*(x
-p1
.x
)
80 if yp
< y
-2 or yp
> y
+2 then
84 local k
= (x
-p1
.x
) / (p2
.x
-p1
.x
)
85 return k
> -0.005 and k
< 1.005
88 function geom
.on_polygon(x
,y
, drawing
, shape
)
90 for _
,p
in ipairs(shape
.vertices
) do
92 if geom
.on_line(x
,y
, drawing
, {p1
=prev
, p2
=p
}) then
98 return geom
.on_line(x
,y
, drawing
, {p1
=shape
.vertices
[1], p2
=shape
.vertices
[#shape
.vertices
]})
101 -- are (x3,y3) and (x4,y4) on the same side of the line between (x1,y1) and (x2,y2)
102 function geom
.same_side(x1
,y1
, x2
,y2
, x3
,y3
, x4
,y4
)
104 return math
.sign(x3
-x1
) == math
.sign(x4
-x1
)
107 return math
.sign(y3
-y1
) == math
.sign(y4
-y1
)
109 local m
= (y2
-y1
)/(x2
-x1
)
110 return math
.sign(m
*(x3
-x1
) + y1
-y3
) == math
.sign(m
*(x4
-x1
) + y1
-y4
)
113 function math
.sign(x
)
123 function geom
.angle_with_hint(x1
, y1
, x2
, y2
, hint
)
124 local result
= geom
.angle(x1
,y1
, x2
,y2
)
126 -- Smooth the discontinuity where angle goes from positive to negative.
127 -- The hint is a memory of which way we drew it last time.
128 while result
> hint
+math
.pi
/10 do
129 result
= result
-math
.pi
*2
131 while result
< hint
-math
.pi
/10 do
132 result
= result
+math
.pi
*2
138 -- result is from -π/2 to 3π/2, approximately adding math.atan2 from Lua 5.3
140 function geom
.angle(x1
,y1
, x2
,y2
)
141 local result
= math
.atan((y2
-y1
)/(x2
-x1
))
143 result
= result
+math
.pi
148 -- is the line between x,y and cx,cy at an angle between s and e?
149 function geom
.angle_between(ox
,oy
, x
,y
, s
,e
)
150 local angle
= geom
.angle(ox
,oy
, x
,y
)
154 -- I'm not sure this is right or ideal..
155 angle
= angle
-math
.pi
*2
156 if s
<= angle
and angle
<= e
then
159 angle
= angle
+math
.pi
*2
160 if s
<= angle
and angle
<= e
then
163 angle
= angle
+math
.pi
*2
164 return s
<= angle
and angle
<= e
167 function geom
.dist(x1
,y1
, x2
,y2
) return ((x2
-x1
)^
2+(y2
-y1
)^
2)^
0.5 end