スプライン その 5
https://ja.wikipedia.org/wiki/B-スプライン曲線 より
B-spline : Basis spline
t ノット m 個の実数
bi,n : B-スプライン基底関数(B-spline basis function)(買った本では,Si,n Ni,d)
bj,0(t) 階数(order)が 1 の時,
t の範囲により,1 または 0 .
bj,n(t)
(t-tj)/(t(j+n)-tj)*(bj,n-1)(t) + (t(j+n+1)-t)/(t(j+n+1)-t(j+1))*(b(j+1,n-1))(t)
Kodatuno の NURBS_Func.cpp NURBS_Func::CalcBSbasis がこれにあたる.
n == 3 制御点は 4
bezier
double t = 1./div_c*index ;
double b0 = (1.-t)*(1.-t)*(1.-t) ; // (1-t)^3
double b1 = 3.*t *(1.-t)*(1.-t) ; // 3 * (1-t)^2 * t
double b2 = 3.*(1.-t)*t*t ; // 3 * (1-t) * t^2
double b3 = t*t*t ; // t^3
double px = (b0*q0.x) + (b1*q1.x) + (b2*q2.x) + (b3*q3.x) ;
double py = (b0*q0.y) + (b1*q1.y) + (b2*q2.y) + (b3*q3.y) ;
double pz = (b0*q0.z) + (b1*q1.z) + (b2*q2.z) + (b3*q3.z) ;
b_spline
double t = 1./div_c*index ;
double n0 = 1./6 * (1.-t)*(1.-t)*(1.-t) ;
double n1 = 1./2 * t*t*t - t*t + 2./3 ;
double n2 =-1./2 * t*t*t + 1./2 * t*t + 1./2 *t + 1./6 ;
double n3 = 1./6 * t*t*t ;
double px = (b0*q0.x) + (b1*q1.x) + (b2*q2.x) + (b3*q3.x) ;
double py = (b0*q0.y) + (b1*q1.y) + (b2*q2.y) + (b3*q3.y) ;
double pz = (b0*q0.z) + (b1*q1.z) + (b2*q2.z) + (b3*q3.z) ;
n == 2
bezier
(1-t)^2
2 * t * (1-t)
t^2
b_spline
1/2 * ( t*t - 2*t + 1)
1/2 * (-2*t*t + 2*t + 1)
1/2 * t*t ;
数学入門 P.163 コックス ド ブールのアルゴリズム
コードのサンプルは,次の所にあったがよくわからず.
https://en.wikipedia.org/wiki/De_Boor's_algorithm
IGES_Parser.cpp
K , M の数は IGES の値に対して +1 している.
N は K + M (IGES の値に対しては K+M+2).
IGES_PARSER::GetNurbsCPara
body.NurbsC[TypeCount[_NURBSC]].K = CatchStringI(&p) + 1; // 総和記号の上側添字(コントロールポイント-1)の値
body.NurbsC[TypeCount[_NURBSC]].M = CatchStringI(&p) + 1; // 基底関数の階数
body.NurbsC[TypeCount[_NURBSC]].N = body.NurbsC[TypeCount[_NURBSC]].K + body.NurbsC[TypeCount[_NURBSC]].M; // ノットベクトルの数
IGES_PARSER::GetNurbsSPara
body.NurbsS[TypeCount[_NURBSS]].K[0] = CatchStringI(&p) + 1; // u方向コントロールポイントの数
body.NurbsS[TypeCount[_NURBSS]].K[1] = CatchStringI(&p) + 1; // v方向コントロールポイントの数
body.NurbsS[TypeCount[_NURBSS]].M[0] = CatchStringI(&p) + 1; // 基底関数のu方向階数
body.NurbsS[TypeCount[_NURBSS]].M[1] = CatchStringI(&p) + 1; // 基底関数のv方向階数
body.NurbsS[TypeCount[_NURBSS]].N[0] = body.NurbsS[TypeCount[_NURBSS]].K[0] + body.NurbsS[TypeCount[_NURBSS]].M[0]; // u方向ノットベクトルの数
body.NurbsS[TypeCount[_NURBSS]].N[1] = body.NurbsS[TypeCount[_NURBSS]].K[1] + body.NurbsS[TypeCount[_NURBSS]].M[1]; // v方向ノットベクトルの数
S , T は N 個.
W , cp は K 個.
ノットベクトル T
コンピュータグラフィックス P.31 より
k+1 個の制御点をもつ n 次 B スプライン曲線の場合には,以下に示すような (n+k+2) 個の要素からなるベクトルとなる.
T = [t0 , t1, ... t(n+k+1)] ( ti≦t(i+1) )
// Function: CalcBSbasis
// Bスプライン基底関数を計算し、計算結果を返す
//
// Parameters:
// t - ノット
// knot[] - ノットベクトル
// N - ノットベクトルの数
// I - Bspl基底関数下添字の1つ目(0~)
// M - 階数(Bspl基底関数下添字の2つ目)
//
// Return:
// 計算結果
double NURBS_Func::CalcBSbasis(double t, double knot[],int N,int I,int M)
{
// 階数(order)が1の時
if(M == 1){
// 注目中のノットの値がノットベクトルの終端値と同じ場合、基底関数が1を取りうる範囲をknot[I+1]も含むようにする
// こうしないと、このときだけ全ての基底関数値が0になってしまう。
if(t==knot[N-1]){
if(knot[I] <= t && t <= knot[I+1]) { return 1.0; }
else { return 0.0; }
}
else{
if(knot[I] <= t && t < knot[I+1]) { return 1.0; }
else { return 0.0; }
}
}
// それ以外の時
else{
double n1=0.0;
double n2=0.0;
double denom;
denom = knot[I+M-1] - knot[I]; // 分母
if(denom > 0.0){
n1 = (t-knot[I])/denom * CalcBSbasis(t,knot,N,I,M-1); // 1項目
}
denom = knot[I+M] - knot[I+1];
if(denom > 0.0){
n2 = (knot[I+M]-t)/denom * CalcBSbasis(t,knot,N,I+1,M-1); // 2項目
}
return(n1+n2);
}
}
参考にさせてもらった所
http://www-mm.hm.t.kanazawa-u.ac.jp/research/kodatuno/
http://ibiblio.org/e-notes/Splines/b-spline.js
https://ci.nii.ac.jp/els/contentscinii_20171206193127.pdf?id=ART0009956858