スプライン曲線とは、簡単に言えばn+1個の点を結ぶ滑らかな曲線の一種です。3次スプライン曲線は、各点と点の間を3次関数で表現し、点での接続が滑らかになるようにしたものです。
以下に単純な
形のスプライン曲線の生成方法を示します。
に対して
が与えられているとします。
に対して、
は
区間
で定義される関数とします。
が
点
と
点
を通り(以下の前提条件の1と2)、
各函数が滑らかに接続する(以下の前提条件の3と4)ように
係数
を決定します。
なお、
関数を一意に決定するために、
以下の前提条件5を追加します。
この
を連結したものが
3次スプライン曲線になります。
前提条件:
に対して、
上記前提条件を元に係数
を計算すると
以下の通りになります。
但し、
です。
![]()
![]()
![]()
は以下の連立1次方程式の解になります。
上記の連立1次方程式は、一般的な解法でも解くことが可能ですが、ほとんどの部分がゼロなので、 処理を最適化すると処理がもっと単純化します(下記プログラム参照)。
空間上の点に対して、点を結ぶスプライン曲線を作れます。
例えば3次元空間上の点の列
に対して
スプライン曲線を作る場合、
を媒介変数として、
各次元毎に分解して
となる
3つのスプライン曲線を作ります。
媒介変数
をどうするかは、
いろいろあると思いますが、
安直に
とするのも一例です。
この場合、
という特殊な条件になるので、
係数
の計算がより楽になります。
![]()
![]()
![]()
を計算する連立1次方程式:

プログラム例を示します。
#define MaxSplineSize 100
class Spline {
int num;
double a[MaxSplineSize+1], b[MaxSplineSize+1], c[MaxSplineSize+1], d[MaxSplineSize+1];
public:
Spline() { num=0; }
void init(double *sp, int num);
double culc(double t);
};
// Bスプライン描画
// x[num], y[num], z[num] は座標の配列
void drowSpline(double *x, double *y, double *z, int num)
{
Spline xs, ys, zs;
double t, m;
xs.init(x, num);
ys.init(y, num);
zs.init(z, num);
m = (double)(num-1);
moveTo(x[0], y[0], z[0])
for(t=0.0; t<=m; t += 0.01) {
lineTo(xs.culc(t), ys.culc(t), zs.culc(t));
}
}
//スプラインデータ初期化
void Spline::init(double *sp, int spnum)
{
double tmp, w[MaxSplineSize+1];
int i;
num = spnum-1;
// 3次多項式の0次係数(a)を設定
for(i=0; i<=num; i++) {
a[i] = sp[i];
}
// 3次多項式の2次係数(c)を計算
// 連立方程式を解く。
// 但し、一般解法でなくスプライン計算にチューニングした方法
c[0] = c[num] = 0.0;
for(i=1; i<num; i++) {
c[i] = 3.0 * (a[i-1] - 2.0 * a[i] + a[i+1]);
}
// 左下を消す
w[0]=0.0;
for(i=1; i<num; i++) {
tmp = 4.0 - w[i-1];
c[i] = (c[i] - c[i-1])/tmp;
w[i] = 1.0 / tmp;
}
// 右上を消す
for(i=num-1; i>0; i--) {
c[i] = c[i] - c[i+1] * w[i];
}
// 3次多項式の1次係数(b)と3次係数(b)を計算
b[num] = d[num] =0.0;
for(i=0; i<num; i++) {
d[i] = ( c[i+1] - c[i]) / 3.0;
b[i] = a[i+1] - a[i] - c[i] - d[i];
}
}
//媒介変数(0〜num-1の実数)に対する値を計算
double Spline::culc(double t)
{
int j;
double dt;
j = (int)floor(t); // 小数点以下切捨て
if(j < 0) j=0; else if (j >= num) j=num-1; // 丸め誤差を考慮
dt = t - (double)j;
return a[j] + ( b[j] + (c[j] + d[j] * dt) * dt ) * dt;
} |
参考リンク
|
|