B-spline基底関数とB-spline曲線のMATLABコード公開

Isogeometric Analysis 有限要素法 NURBS プログラミング

今回はB-spline基底関数とB-spline曲線をMATLABで描写していきます。

この記事はこんな人にオススメ
  • B-spline基底関数、B-spline曲線の具体的なコードが知りたい
  • コード例を見てMATLABの組み込み関数について理解したい
トライ
トライ

B-spline曲線の概要については前回の記事で詳しく解説しているので、B-spline曲線の概要を理解していない方はまずはそちらからご覧ください。

MATLABコード公開

B-spline基底関数

まずはB-spline曲線を構成する基底関数であるB-spline基底関数のコードを公開します。

おさらいとして、B-spline基底関数は以下の式で表されます。

Isogeometric Analysis 有限要素法 NURBS B-spline

これをMATLABで新規関数として定義します。以下のコードをコピーしてmファイルとして保存して下さい。

保存する際のファイル名は以下の【】に示すように「bsplinebasisfunction.m」として下さい。

【bsplinebasisfunction.m】

function N = bsplinebasisfunction(i,p,xi,knot)
    if p == 0
        if knot(i) <= xi && xi < knot(i+1)
            N = 1;
        else
            N = 0;
        end
    else
        Np1 = bsplinebasisfunction(i,p-1,xi,knot);
        Np2 = bsplinebasisfunction(i+1,p-1,xi,knot);
        if knot(i+p) == knot(i) % define 0/0 = 0
            fterm = 0;
        else
            fterm = ( (xi-knot(i)) / (knot(i+p)-knot(i)) ) * Np1;
        end
        if knot(i+p+1) == knot(i+1) % define 0/0 = 0
            sterm = 0;
        else
            sterm = ( (knot(i+p+1)-xi) / (knot(i+p+1)-knot(i+1)) ) * Np2;
        end
        N = fterm + sterm;
    end
end

後で解説しますが、上記のコードのみだと正しい結果が出ないため、もうひとつ、補正用のコードとして「bsplinebasisfunction1.m」も併せて保存しておいて下さい。

【bsplinebasisifunction1.m】

function N = bsplinebasisfunction1(i,p,xi,knot)
    if p == 0
        if knot(i) <= xi && xi <= knot(i+1)
            N = 1;
        else
            N = 0;
        end
    else
        Np1 = bsplinebasisfunction1(i,p-1,xi,knot);
        Np2 = bsplinebasisfunction1(i+1,p-1,xi,knot);
        if knot(i+p) == knot(i) % define 0/0 = 0
            fterm = 0;
        else
            fterm = ( (xi-knot(i)) / (knot(i+p)-knot(i)) ) * Np1;
        end
        if knot(i+p+1) == knot(i+1) % define 0/0 = 0
            sterm = 0;
        else
            sterm = ( (knot(i+p+1)-xi) / (knot(i+p+1)-knot(i+1)) ) * Np2;
        end
        N = fterm + sterm;
    end
end

トライ
トライ

「bspinebasisfunction.m」と「bspinebasisfunction1.m」の違いは、3行目の if 文の後半が「xi < knot(i+1)」なのか「xi <= knot(i+1)」なのかの違いのみです。

メインプログラム

次にB-spline基底関数およびB-spline曲線のメインプログラムを公開します。

こちらもおさらいとして、B-spline曲線は以下の式で表されます。

Isogeometric Analysis 有限要素法 NURBS B-spline

メインプログラムのファイル名は何でも大丈夫です。

自分の分かりやすい名前をつけて、先ほど公開したB-spline基底関数のコードと同じファイル内に以下のコードを保存して下さい。

今回はB-spline基底関数 Ni,p(ξ) とB-spline曲線 C(ξ) のメインプログラムなので「main_N_C.m」とします。

【main_N_C.m】

clear

n = 8; % 制御点数 n
p = 2; % 曲線次数 p
knot = [0 0 0 1 2 3 4 4 5 5 5]; % ノットベクトル
xi = linspace(0,5,500); % size 500

P = [ 3  3  0;    6  1  0;      9   1  0;
      9  5  0;   12  5  0;   16.5 9.5  0;
      9 13  0;    6  8  0              ];

N = zeros( n, length(xi) );

Cx0 = zeros( size(xi) ); Cy0 = zeros( size(xi) );
Cx  = zeros( size(xi) ); Cy  = zeros( size(xi) );

for j = 1:length(xi)
    Cx(j) = 0;
    Cy(j) = 0;
    for i = 1:n
        if j == length(xi)
            N(i,j) = bsplinebasisfunction1(i,p,xi(j),knot);
        else
            N(i,j) = bsplinebasisfunction(i,p,xi(j),knot);
        end
        Cx0(j) = N(i,j) * P(i,1);
        Cy0(j) = N(i,j) * P(i,2);
        Cx(j) = Cx(j) + Cx0(j);
        Cy(j) = Cy(j) + Cy0(j);
    end
end

% B-spline基底関数をプロットする
figure(1); cla
plot(xi,N,'LineWidth',1.5)
axis equal;
axis([0 5 0 1])
xlabel('ξ','FontSize',20); ylabel('N(ξ)','FontSize',20);
title('B-Spline Basis Function','FontSize',20)
set(gca,'FontSize',20);
hold off

% B-spline曲線をプロット
figure(2); cla
% 制御多角形をプロット
plot(P(:,1),P(:,2),'k');
hold on
% 制御点をプロット
plot(P(:,1),P(:,2),'ro','markerFaceColor','red','markersize',4);
% 曲線をプロット
plot(Cx,Cy,'b','LineWidth',2)
axis([0 18 0 15])

% 各軸の名前と図の凡例を追記
xlabel('x','FontSize',18)
ylabel('y','FontSize',18)
title('B-Spline Curve','FontSize',18)
set(gca,'FontSize',18);
hanrei = legend('Control Polygon','B-Spline Curve','Conrtol Points');
set(hanrei,'Location','NorthWest','FontSize',10)
hold off

公開コードの解説

各変数の設定

メインプログラム冒頭の3-5行目で、B-spline基底関数を構成する以下の3つの変数を定義します。

  • 制御点の数 n
  • B-spline基底関数(B-spline曲線)の次数 p
  • ノットベクトル Ξ

制御点の数 n は描写したい図の通り8個、曲線の次数 p は2次とします。

ノットベクトル Ξ については以下のルールを再確認しておきます。

  • ノットベクトルの長さは n+p+1 とする。
  • ノットベクトルの値は単純増加(値が減少しない)とする。
  • 多重度を導入する場合を除き、増加間隔は等間隔とする。
  • 領域の端部(始点と終点)はノットを p+1個重複(=多重度 p+1)させる。
  • 制御点を通過させたい場合はノットを p個重複(=多重度 p)させる。

これらのルールを踏まえ、ノットベクトル Ξ = { 0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5 } としています。

MATLAB組み込み関数:linspace

【4行目】

xi = linspace(0,5,500);

ここではMATLABの組み込み関数「linspace」(linear space:線形空間)を使って ξ の値を定義しています。

「linspace」を使うことで、指定した区間を等分割することができます。

今回の場合は「0から5までの区間を500分割する」という意味となり、ξ のサイズは1行500列となります。

似たような記述方法として、「xi = 0:0.01:500」という方法もあります。

これは「0から0.01刻みで500まで並べる」という意味になるため、 ξ のサイズは1行501列となります。

トライ
トライ
  • ベクトル ξサイズをキリ良くしたいなら「xi = linspace(0,5,500)」
  • ベクトル ξ各値をキリ良くしたいなら「xi = 0:0.01:500」

といった感じで使い分けると良いでしょう。

また、変数 ξ の間隔は0.01か0.02刻みくらいだとキレイな曲線が描けます。

変数のサイズを定義する

【12-14行目】

N = zeros( n, length(xi) );

Cx0 = zeros( size(xi) ); Cy0 = zeros( size(xi) );

Cx  = zeros( size(xi) ); Cy  = zeros( size(xi) );

12行目から14行目にかけて、この後計算する変数のサイズを予め定義しています。

この工程は必須ではありませんが、変数のサイズを予め定義しておくことで、解析時間を短縮することができます。

トライ
トライ

forループが進むたびに変数のサイズが変わる計算はCPUに負担がかかり、計算時間が長くなってしまいます。

最初に変数のサイズを指定(このとき、各値はすべて0)し、各値を計算して代入していくほうが計算速度が速くなります。

補正用コード:bsplinebasisifunction1.m

【16-20行目】

for j = 1:length(xi)
    Cx(j) = 0;
    Cy(j) = 0;
    for i = 1:n
        if j == length(xi)
            N(i,j) = bsplinebasisfunction1(i,p,xi(j),knot);
        else
            N(i,j) = bsplinebasisfunction(i,p,xi(j),knot);
        end
        Cx0(j) = N(i,j) * B(i,1);
        Cy0(j) = N(i,j) * B(i,2);
        Cx(j) = Cx(j) + Cx0(j);
        Cy(j) = Cy(j) + Cy0(j);
    end
end

先ほど公開した補正用のコードについて説明します。

実際に「bsplinebasisfunction.m」のみを用いた場合と、補正用コードを用いた場合のB-spline基底関数を比較します。

Isogeometric Analysis 有限要素法 NURBS B-spline
「bsplinebasisfunction.m」のみを用いた場合のB-spline基底関数
Isogeometric Analysis 有限要素法 NURBS B-spline
補正関数を用いた場合のB-spline基底関数

トライ
トライ

左図と右図の違い、分かりますか?

実はCox-de Boorの式をそのままコードとして書くと、左図のようなB-spline基底関数が返ってきます。

左図のB-spline基底関数のマズいところは、ξ = 5 のときの N(ξ) の値が 0 になってしまっているところです。

これに気付かずにB-spline曲線を描くと、下の左図のようにセグメントの最後の値が 0 になってしまいます。

補正関数を用いた正しい結果図が下の右図となります。

Isogeometric Analysis 有限要素法 NURBS B-spline
「bsplinebasisfunction.m」のみを用いた場合のB-spline曲線
Isogeometric Analysis 有限要素法 NURBS B-spline
補正関数を用いた場合のB-spline曲線

まとめ

今回はB-spline基底関数とB-spline曲線のMATLABコード例を公開し、コードについて解説しました。

B-spline基底関数はデザイン分野で最もよく使用されるNURBS関数やIsogeometric Analysisの基本となる非常に汎用性の高い関数です。

また、MATLABは結果の図示方法が非常に充実しています。

すべては紹介しきれませんが、これまで公開してきたコードの中で様々な使用例を載せていますので参考にしてください。

最後までお読みいただきありがとうございました。

コメント

タイトルとURLをコピーしました