Bezier.lua 2.6 KB
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