2014年9月3日水曜日

Catmull-Rom曲線をBezier曲線に変換する

面倒な能書きは止めた.Catmull-Rom曲線は3次のBezier(ベジェ)曲線に簡単に変換出来るという実演.本スクリプトを組み込むことでSVGやcanvas要素でCatmull-Rom曲線を扱うことが可能になります.

※個人的なメモですので,間違いがあるかも知れません.
9/5 バグ修正

コードを見る

Catmull-Rom曲線の制御点からBezier曲線の制御点を算出するには次の関数を実行します.
(用途に応じて適宜書き換えてお使いください.※ライセンスフリー 煮るなり焼くなり)


//see http://t-pot.com/program/2_3rdcurve/index.html
function toBezier(p0, p1, p2, p3){
 var B,C;
 if(p0 === undefined){
  //first point
  B = 1/2*p1 - p2 + 1/2*p3;
  C = -3/2*p1 + 2*p2 - 1/2*p3;
 }else if(p3 === undefined){
  //end point
  B = 1/2*p0 - p1 + 1/2*p2;
  C = -1/2*p0 + 1/2*p2;
 }else{
  B = p0 - 5/2*p1 + 4/2*p2 - 1/2*p3;
  C = -1/2*p0 + 1/2*p2;
 }
 var P1 = (C + 3*p1)/3;
 var P2 = (B - 3*p1 + 6*P1)/3;
 return {p1:P1, p2:P2};
}

使い方

Catmull-Rom曲線では4点「P0-P1-P2-P3」の4つの座標から「P1-P2」間の曲線を得ます.
そこで関数toBezierにそれぞれのx座標(もしくはy座標)を渡すことでBezier曲線の制御点(S1,S2)の座標が得られます.
※得られたBezier曲線は「P1-S1-S2-P2」 となります.
※パスの始点及び終点には一個前/後の座標が存在しないので,引数としてはundefinedを渡してください.

実行例





カラクリ


詳しい証明はよそに譲るとして,要は次のような理屈によって動いています.

http://t-pot.com/program/2_3rdcurve/index.html
によれば,媒介変数tを用いてBezier曲線とCatmull-Rom曲線を表すと次のようになります.
p1,p2…曲線を引きたい座標
p0…p1の一つ前の座標
p3…p2の一つ後の座標
s1,s2…Bezier曲線における制御点の座標…求めたい対象

Bezier曲線
P(t) = (-p1 + 3s1 - 3s2 + p2)t3 + (3p1 - 6s1 + 3s2)t2 + (-3p1 + 3s1)t + p1---(1)

Catmull-rom曲線
P(t) = (-1/2p0 + 3/2p1 -3/2p2 + 1/2p3)t3 + (p0 - 5/2p1 + 2p2 -1/2p3)t2 + (-1/2p0 + 1/2p2)t + p1---(2)

※始点
P(t) = (1/2p1 - p2 + 1/2p3)t2 + (-3/2p1 + 2p2 - 1/2p3)t + p1---(2')

※終点
P(t) = (1/2p0 - p1 + 1/2p2)t2 + (-1/2p0 + 1/2p2)t + p1---(2'')

ここで(1)と(2)は同じ図形を表すのですから,t^2及びtの係数は一致するはずです.よって次の関係が成り立ちます.

-3p1 + 3s1 = -1/2p0 + 1/2p2
3p1 - 6s1 + 3s2 = p0 - 5/2p1 + 2p2 -1/2p3

この時p0〜p3の値は予め判っていますからこの連立方程式を解けば制御点の座標が求まるのです.
※最初と最後のパス切片においては計算式が変化します.

0 件のコメント:

コメントを投稿