ベジェ曲線による近似

Top »

二次ベジェ曲線による関数の近似

y=f(x) で表示される曲線の適当な区間 x=[a,b] を二次ベジェ曲線で近似してみる。

ベジェ曲線の座標はx1,y1,x2,y2,x3,y3とする。始点は(x1,y1) = (a,f(a))、終点は(x3,y3) = (b,f(b))とする。問題は制御点(x2,y2)の算出である。x=a,bに於ける傾きが元の関数に一致させるために、制御点はx=a,bに於けるそれぞれの接線の交点とするとよい。

x=a に於ける接線:「一点を通り任意の傾きの直線」より

y - y1 = m*(x - x1)

ここで点 (x1,y1) = (a,f(a)) 、傾き m = d(f(x))/dx = f'(a) だから

y-f(a) = f'(a)*(x-a)
f'(a)*x - y - f'(a)*a + f(a) = 0

x=b に於ける接線も同様:

f'(b)*x - y - f'(b)*b + f(b) = 0

上記二式を満たす(x,y)が制御点(x2,y2)である。これを i*x+j*y+k=0, l*x+m*y+n=0 とみなすと

i = f'(a), j = -1, k = - f'(a)*a + f(a),
l = f'(b), m = -1, n = - f'(b)*b + f(b)

この解は

x = x2 = (-n*j+k*m)/(j*l-i*m) = (n-k)/(f'(a)-f'(b))
y = y2 = ( n*i-k*l)/(j*l-i*m) = (n*f'(a)-k*f'(b))/(f'(a)-f'(b))

実装(仕様:JavaScriptでf(x)をa~bをn分割し二次ベジェ曲線で近似し制御点・終点をSVG的に出力)

cx = 100;
cy = 380;
scaling = 100;
a = -1;
b = 4;
n = 6;
function f(x) {
	return -(3-x)*(2-x)*x;
}
function fd(x) {
	return -3*x*x+10*x-6;
}
var x = a;
var k = -fd(x)*x+f(x);
document.write("M\t\t\t"+(x*scaling+cx)+"\t"+(f(x)*scaling+cy)+"\nQ");
for (var i = 1; i<=n; i++) {
	var xp = x;
	var kp = k;
	var x = i/n*(b-a)+a;
	var k = -fd(x)*x+f(x);
	var x2 = (k-kp)/(fd(xp)-fd(x));
	var y2 = (k*fd(xp)-kp*fd(x))/(fd(xp)-fd(x));
	document.write("\t"+(x2*scaling+cx)+"\t"+(y2*scaling+cy)+"\t"+(x*scaling+cx)+"\t"+(f(x)*scaling+cy)+"\n");
}

このままだと、始点・終点の傾きが近いときに算出される制御点が無限遠に飛んでバグる。

二次ベジェ曲線によるパラメトリック曲線の近似

媒介変数曲線 x=x(t), y=y(t) で表示される曲線の適当な区間 t=[a,b] を二次ベジェ曲線で近似してみる。

ベジェ曲線の座標はx1,y1,x2,y2,x3,y3とする。始点は(x1,y1) = (x(a),y(a))、終点は(x3,y3) = (x(b),y(b))とする。問題は制御点(x2,y2)の算出である。t=a,bに於ける傾きが元の関数に一致させるために、制御点はt=a,bに於けるそれぞれの接線の交点とするとよい。

t=a に於ける接線:「一点を通り任意の傾きの直線」より

y - y1 = m*(x - x1)

ここで点 (x1,y1) = (x(a),y(a)) 、傾き m = (d(y(t))/dt)/(d(x(t))/dt) = y'(a)/x'(a) だから

y-y(a) = y'(a)/x'(a)*(x-x(a))
y'(a)*x - x'(a)*y - y'(a)*x(a) + x'(a)*y(a) = 0

t=b に於ける接線も同様:

y'(b)*x - x'(b)*y - y'(b)*x(b) + x'(b)*y(b) = 0

上記二式を満たす(x,y)が制御点(x2,y2)である。これを i*x+j*y+k=0, l*x+m*y+n=0 とみなすと

i = y'(a), j = -x'(a), k = -y'(a)*x(a)+x'(a)*y(a),
l = y'(b), m = -x'(b), n = -y'(b)*x(b)+x'(b)*y(b)

この解は

x = x2 = (-n*j+k*m)/(j*l-i*m) = (n*x'(a)-k*x'(b))/(y'(a)*x'(b)-x'(a)*y'(b))
y = y2 = ( n*i-k*l)/(j*l-i*m) = (n*y'(a)-k*y'(b))/(y'(a)*x'(b)-x'(a)*y'(b))

inserted by FC2 system