/
BezierCurve.lua
169 lines (149 loc) · 4.23 KB
/
BezierCurve.lua
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
--==============================
-- Bezier Curve Class
--==============================
-- Created by: E.T. Garcia
-- Created on: 2/14/2012
local BezierCurve = {}
function BezierCurve.new(p0, c0, p1, c1, isDebug)
-- Creates Instance
local self = {}
--==============================
-- Public Variables
--==============================
self.gfx = nil
--==============================
-- Local Variables
--==============================
local isDebug = isDebug or false
local p0 = display.newCircle(p0.x, p0.y, 5)
local p1 = display.newCircle(p1.x, p1.y, 5)
local c0 = display.newCircle(c0.x, c0.y, 5)
local c1 = display.newCircle(c1.x, c1.y, 5)
local hasMoved = false
local handles = {p0, p1, c0, c1}
local color = {255,128,0}
local lines
--==============================
-- Local Functions
--==============================
-- Returns the square distance between two points
local function sqDist(pt0, pt1)
local dx = pt0.x - pt1.x
local dy = pt0.y - pt1.y
return dx*dx + dy*dy
end
-- Calculates line segments and draws them (into self.gfx)
local function drawBezier(granularity, r, g, b)
-- Setup Variables
granularity = granularity or 50
r = r or color[1]
g = g or color[2]
b = b or color[3]
local segments = {}
local p = bezierPoints
local inc = (1.0 / granularity)
local t = 0
local t1 = 0
-- For granularity, complete crazy formula to compute segments
for i = 1, granularity do
t1 = 1.0 - t
local x = (t1*t1*t1) * p0.x
x = x + (3*t)*(t1*t1) * c0.x
x = x + (3*t*t)*(t1) * c1.x
x = x + (t*t*t) * p1.x
local y = (t1*t1*t1) * p0.y
y = y + (3*t)*(t1*t1) * c0.y
y = y + (3*t*t)*(t1) * c1.y
y = y + (t*t*t) * p1.y
table.insert(segments, {x = x, y = y})
t = t + inc
end
-- Add last segment if it doesn't quite reach the last point
if (sqDist(segments[#segments],p1) < 10*10) then --if close, just change last point to end point
segments[#segments] = {x = p1.x, y = p1.y}
else --otherwise, add the last point
table.insert(segments, {x = p1.x, y = p1.y})
end
-- Remove previous bezierCurve and draw segments
if (self.gfx) then self.gfx:removeSelf() end
self.gfx = display.newLine(segments[1].x, segments[1].y, segments[2].x, segments[2].y)
for i = 3, #segments do
self.gfx:append(segments[i].x, segments[i].y)
end
-- Set color and width of bezier curve (aka lines)
self.gfx:setColor(r,g,b)
self.gfx.width = 4
end
-- Move debug handles around
local function dragHandles(event)
local t = event.target
if (event.phase == "began") then
t.parent:insert(t)
display.getCurrentStage():setFocus(t)
t.isFocus = true
elseif (t.isFocus) then
if (event.phase == "moved") then
t.x = event.x
t.y = event.y
hasMoved = true
elseif (event.phase == "ended" or event.phase == "cancelled") then
display.getCurrentStage():setFocus(nil)
t.isFocus = false
hasMoved = false
drawBezier()
end
end
end
-- Redraw curve if moved
local function update(event)
if (hasMoved) then
hasMoved = false
if (lines) then lines:removeSelf() end
lines = display.newGroup()
display.newLine(lines,p0.x,p0.y,c0.x,c0.y)
display.newLine(lines,p1.x,p1.y,c1.x,c1.y)
drawBezier(10,128,128,128)
end
end
--==============================
-- Public Functions
--==============================
function self:toggleDebug()
if (isDebug) then
for i = 1, #handles do
handles[i].isVisible = true
handles[i]:addEventListener("touch", dragHandles)
end
Runtime:addEventListener("enterFrame", update)
else
Runtime:removeEventListener("enterFrame", update)
for i = 1, #handles do
handles[i].isVisible = false
handles[i]:removeEventListener("touch", dragHandles)
end
end
hasMoved = true
isDebug = not(isDebug)
end
function self:removeSelf()
if (self.gfx) then self.gfx:removeSelf() end
for i = 1, #handles do
if (handles[i]) then handles[i]:removeSelf() end
end
self.gfx = nil
handles = nil
colors = nil
end
--==============================
-- Constructor
--==============================
p0:setFillColor(255,0,0)
p1:setFillColor(255,0,0)
c0:setFillColor(255,255,0)
c1:setFillColor(255,255,0)
self:toggleDebug(isDebug)
drawBezier()
-- Return Instance
return self
end
return BezierCurve