Bezier.lua
2.6 KB
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
cc.exports.Bezier = {}
--起点,控制点,终点,分割份数
local p0,p1,p2,step;
local ax,ay,bx,by,A,B,C,_total_length;
-- 速度函数
local function s(t)
return math.sqrt(A * t * t + B * t + C);
end
-- 长度函数
local function L(t)
local temp1 = math.sqrt(C + t * (B + A * t));
local temp2 = (2 * A * t * temp1 + B *(temp1 - math.sqrt(C)));
local temp3 = math.log(B + 2 * math.sqrt(A) * math.sqrt(C));
local temp4 = math.log(B + 2 * A * t + 2 * math.sqrt(A) * temp1);
local temp5 = 2 * math.sqrt(A) * temp2;
local temp6 = (B * B - 4 * A * C) * (temp3 - temp4);
return (temp5 + temp6) / (8 * math.pow(A, 1.5));
end
-- 长度函数反函数,使用牛顿切线法求解
local function InvertL(t, l)
local t1 = t;
local t2;
while(true)
do
local _s = s(t1);
t2 = t1 - (L(t1) - l)/_s;
if (math.abs(t1-t2) < 0.000001 or t1==nil or t2==nil) then
break;
end
t1 = t2;
end
return t2;
end
-- 返回所需总步数
function Bezier:init(_p0, _p1, _p2, _speed)
p0 = _p0;
p1 = _p1;
p2 = _p2;
ax = p0.x - 2 * p1.x + p2.x;
ay = p0.y - 2 * p1.y + p2.y;
bx = 2 * p1.x - 2 * p0.x;
by = 2 * p1.y - 2 * p0.y;
A = 4*(ax * ax + ay * ay);
B = 4*(ax * bx + ay * by);
C = bx * bx + by * by;
-- 计算长度
_total_length = L(1);
-- 计算步数
step = math.floor(_total_length / _speed);
if (_total_length % _speed > _speed / 2) then
step = step+1;
end
-- print("曲长:" + total_length);
-- print("步数:" + step);
return step;
end
-- 根据指定nIndex位置获取锚点:返回坐标和角度
function Bezier:getAnchorPoint(nIndex)
if (nIndex >= 0 and nIndex <= step) then
local t = nIndex/step
-- 如果按照线行增长,此时对应的曲线长度
local l = t*_total_length
-- 根据L函数的反函数,求得l对应的t值
t = InvertL(t, l);
-- 根据贝塞尔曲线函数,求得取得此时的x,y坐标
local xx = (1 - t) * (1 - t) * p0.x + 2 * (1 - t) * t * p1.x + t * t * p2.x;
local yy = (1 - t) * (1 - t) * p0.y + 2 * (1 - t) * t * p1.y + t * t * p2.y;
return Point.new(xx,yy);
-- // 获取切线
-- var Q0:Point = new Point((1 - t) * p0.x + t * p1.x, (1 - t) * p0.y + t * p1.y);
-- var Q1:Point = new Point((1 - t) * p1.x + t * p2.x, (1 - t) * p1.y + t * p2.y);
--
-- // 计算角度
-- var dx:Number = Q1.x - Q0.x;
-- var dy:Number = Q1.y - Q0.y;
-- var radians:Number = math.atan2(dy, dx);
-- var degrees:Number = radians * 180 / math.PI;
-- return new Array(xx, yy, degrees);
else
return Point.new();
end
end
function Bezier:total_length()
return _total_length;
end
return Bezier