support selections in the source editor
[view.love.git] / geom.lua
blob891e98d01127b78f1ac1ecac9b43a6922e08ca4f
1 geom = {}
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]
11 if p1.x == p2.x then
12 if x ~= p1.x then return false end
13 local y1,y2 = p1.y, p2.y
14 if y1 > y2 then
15 y1,y2 = y2,y1
16 end
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
21 if x1 > x2 then
22 x1,x2 = x2,x1
23 end
24 return x >= x1-2 and x <= x2+2
25 end
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
36 return false
37 end
38 return geom.angle_between(center.x,center.y, x,y, shape.start_angle,shape.end_angle)
39 elseif shape.mode == 'deleted' then
40 else
41 print(shape.mode)
42 assert(false)
43 end
44 end
46 function geom.on_freehand(x,y, drawing, shape)
47 local prev
48 for _,p in ipairs(shape.points) do
49 if prev then
50 if geom.on_line(x,y, drawing, {p1=prev, p2=p}) then
51 return true
52 end
53 end
54 prev = p
55 end
56 return false
57 end
59 function geom.on_line(x,y, drawing, shape)
60 local p1,p2
61 if type(shape.p1) == 'number' then
62 p1 = drawing.points[shape.p1]
63 p2 = drawing.points[shape.p2]
64 else
65 p1 = shape.p1
66 p2 = shape.p2
67 end
68 if p1.x == p2.x then
69 if math.abs(p1.x-x) > 2 then
70 return false
71 end
72 local y1,y2 = p1.y,p2.y
73 if y1 > y2 then
74 y1,y2 = y2,y1
75 end
76 return y >= y1-2 and y <= y2+2
77 end
78 -- has the right slope and intercept
79 local m = (p2.y - p1.y) / (p2.x - p1.x)
80 local yp = p1.y + m*(x-p1.x)
81 if yp < y-2 or yp > y+2 then
82 return false
83 end
84 -- between endpoints
85 local k = (x-p1.x) / (p2.x-p1.x)
86 return k > -0.005 and k < 1.005
87 end
89 function geom.on_polygon(x,y, drawing, shape)
90 local prev
91 for _,p in ipairs(shape.vertices) do
92 if prev then
93 if geom.on_line(x,y, drawing, {p1=prev, p2=p}) then
94 return true
95 end
96 end
97 prev = p
98 end
99 return geom.on_line(x,y, drawing, {p1=shape.vertices[1], p2=shape.vertices[#shape.vertices]})
102 -- are (x3,y3) and (x4,y4) on the same side of the line between (x1,y1) and (x2,y2)
103 function geom.same_side(x1,y1, x2,y2, x3,y3, x4,y4)
104 if x1 == x2 then
105 return math.sign(x3-x1) == math.sign(x4-x1)
107 if y1 == y2 then
108 return math.sign(y3-y1) == math.sign(y4-y1)
110 local m = (y2-y1)/(x2-x1)
111 return math.sign(m*(x3-x1) + y1-y3) == math.sign(m*(x4-x1) + y1-y4)
114 function math.sign(x)
115 if x > 0 then
116 return 1
117 elseif x == 0 then
118 return 0
119 elseif x < 0 then
120 return -1
124 function geom.angle_with_hint(x1, y1, x2, y2, hint)
125 local result = geom.angle(x1,y1, x2,y2)
126 if hint then
127 -- Smooth the discontinuity where angle goes from positive to negative.
128 -- The hint is a memory of which way we drew it last time.
129 while result > hint+math.pi/10 do
130 result = result-math.pi*2
132 while result < hint-math.pi/10 do
133 result = result+math.pi*2
136 return result
139 -- result is from -π/2 to 3π/2, approximately adding math.atan2 from Lua 5.3
140 -- (LÖVE is Lua 5.1)
141 function geom.angle(x1,y1, x2,y2)
142 local result = math.atan((y2-y1)/(x2-x1))
143 if x2 < x1 then
144 result = result+math.pi
146 return result
149 -- is the line between x,y and cx,cy at an angle between s and e?
150 function geom.angle_between(ox,oy, x,y, s,e)
151 local angle = geom.angle(ox,oy, x,y)
152 if s > e then
153 s,e = e,s
155 -- I'm not sure this is right or ideal..
156 angle = angle-math.pi*2
157 if s <= angle and angle <= e then
158 return true
160 angle = angle+math.pi*2
161 if s <= angle and angle <= e then
162 return true
164 angle = angle+math.pi*2
165 return s <= angle and angle <= e
168 function geom.dist(x1,y1, x2,y2) return ((x2-x1)^2+(y2-y1)^2)^0.5 end