二次ベジェ曲線の長さ

Top »

二次ベジェ曲線の長さは正確に解析解を求めることが可能である。

t が微小変化するときの長さは、ピタゴラスの定理により

√((dx/dt)^2+(dy/dt)^2)

これを t=t1~t2 で定積分すれば長さが求まる。

∫[t1,t2] √((dx/dt)^2+(dy/dt)^2) dt

二次ベジェ曲線のxおよびyをtで微分すると

dx/dt = 2(x1-2x2+x3)t + (-2x1+2x2)
dy/dt = 2(y1-2y2+y3)t + (-2y1+2y2)

ここでtの係数を

xa = 2(x1-2x2+x3), xb = -2x1+2x2,
ya = 2(y1-2y2+y3), yb = -2y1+2y2

とおくと

(dx/dt)^2+(dy/dt)^2
= (xat+xb)^2 + (yat+yb)^2
= xa^2t^2+2xaxbt+xb^2 + ya^2t^2+2yaybt+yb^2
= (xa^2+ya^2)t^2 + (2(xaxb+yayb))t + (xb^2+yb^2)

ここでさらにtの係数を

a = xa^2+ya^2, b = 2(xaxb+yayb), c = xb^2+yb^2

とおくと

∫[t1,t2]√(at^2+bt+c) dt

二次式の平方根を積分する問題になる。

一般のとき

置換積分 (s-b)/(2√(a))-√(a)t = √(at^2+bt+c)

両辺二乗 (s-b)^2/(4a)-(s-b)t+at^2 = at^2+bt+c
tを解く t=(s^2-2bs-4ac+b^2)/(4as)
uで微分 dt=(s^2+4ac-b^2)/(4as^2)du
積分区間は s=2(√(a(t(at+b)+c))+at)+b によって変更

これを使って

∫[t1,t2]√(at^2+bt+c) dt
=∫[t1,t2](s-b)/(2√(a))-√(a)t dt
=∫[s1,s2]((s-b)/(2√(a))-√(a)(s^2-2bs-4ac+b^2)/(4as))(s^2+4ac-b^2)/(4as^2) ds

整理

=1/(16a^(3/2))∫[s1,s2](s^2+4ac-b^2)^2/s^3 ds

ここで D=b^2-4ac とおく

=1/(16a^(3/2))∫[s1,s2](s^2-D)^2/s^3 ds
=1/(16a^(3/2))∫[s1,s2]D^2/s^3-2D/s+s ds
=1/(16a^(3/2))[-D^2/(2s^2)-2D log(s)+s^2/2][s=s1,s2]
=1/(16a^(3/2))(-D^2/2 (1/s2^2-1/s1^2)-2D(log(s2)-log(s1))+(s2^2-s1^2)/2)

処理削減を図る

=(s2*s2-s1*s1-D*(4*log(s2/s1)+D*(1/(s2*s2)-1/(s1*s1))))/(32*a*√(a))

D==0のとき

制御点が一直線に並ぶ場合,s2かs1がほとんど必ず0になりlogが-無限大に飛ぶ。

∫[t1,t2]√(at^2+bt+c)dt

b^2-4ac=0によりc=b^2/(4a)を代入

=∫[t1,t2]√(ax^2+bx+(b^2/(4a))) dx
=1/(2√(a))∫|2ax+b|dx

置換積分 u = 2ax+b,dx = 1/(2a) du

=1/(4a√(a))∫|u|du
=1/(8a√(a))[|u|u][t=t1,t2]
=1/(8a√(a))[|2at+b|(2at+b)][t=t1,t2]
=1/(8a√(a))[|2at2+b|(2at2+b)-|2at1+b|(2at1+b)][t=t1,t2]

a==0のとき

特に第二制御点が中間にあるときa=0かつb=0となるので上の式は0除算となる。

∫[t1,t2]√(c)dx
=√(c)(t2-t1)

実装

//二次ベジェ曲線の長さを返す
// x1, y1, x2, y2, x3, y3: 制御点座標
// t2: 終点t 省略時1
// t1: 始点t 省略時0
function getLengthQ2(x1, y1, x2, y2, x3, y3, t2, t1) {
	if (t2 == undefined) t2 = 1;
	if (t1 == undefined) t1 = 0;
	var xa = 2*(x1-2*x2+x3), xb = -2*x1+2*x2, ya = 2*(y1-2*y2+y3), yb = -2*y1+2*y2;
	var a = xa*xa+ya*ya, b = 2*(xa*xb+ya*yb), c = xb*xb+yb*yb, D = b*b-4*a*c;
	if (D) {
		var s1 = 2*Math.sqrt(a*(t1*(a*t1+b)+c))+2*a*t1+b;
		var s2 = 2*Math.sqrt(a*(t2*(a*t2+b)+c))+2*a*t2+b;
		return (s2*s2-s1*s1-D*(4*Math.log(s2/s1)+D*(1/(s2*s2)-1/(s1*s1))))/(32*a*Math.sqrt(a));
	} else if (a) {
		return (Math.abs(2*a*t2+b)*(2*a*t2+b)-Math.abs(2*a*t1+b)*(2*a*t1+b))/(8*a*Math.sqrt(a));
	} else {
		return Math.sqrt(c)*(t2-t1);
	}
}

ベジェ曲線の分割と組み合わせ、0~tの長さ、被積分関数√(at^2+bt+c)、変数変換s=2(√(a(t(at+b)+c))+at)+bもプロットしてみた。

参考:quadratic Bezier curve length ≪ Playground ≪ segfaultlabs

inserted by FC2 system