ベジエ曲線(ベジェ曲線)について

WAKWAKに設置していたサイトからの転載(一部改訂)です。)



 Adobe Illustrator で描かれる曲線はベジエ曲線(3次ベジエ曲線)というもので、図のようにアンカー2点+ハンドル2点の計4点の座標を元にして描かれる曲線です。「ベジエ」とは、この曲線を自動車のCAD (Computer Aided Design) に応用した仏人 Pierre Bézier さんに由来するそうです。


 別に何次の何曲線だろうが、Illustrator を使うときには関係ないだろう、と思われる向きもあるかと思いますが、この曲線のいくつかの性質は、知っておくと役立つことがあると思います。例えば「ハンドルは必ずアンカーの位置での接線になる」、「曲線は必ず4点を結ぶ四角形の内側に描かれる」といったことがそれです。


 メニューから「アンカーポイントの追加」を実行したときに追加されるアンカーの位置はパスの中点とは限らず、気まぐれな位置に追加されてるような気もしますが、これもベジエ曲線の仕組みから考えれば、それなりに根拠のある位置なのだとわかります。


 だ円ツールで描いた円は、正確な円ではなく若干歪みがあるのですが、実際のところ、どのくらい歪んでいるのでしょうか。これもベジエ曲線を表す式から割り出すことができます。

数式で表すの巻


 図のようなアンカーとハンドルを持つベジエ曲線は、実際どのように描かれているんだろうか?という話です。コンピュータがやってることなので、適当に滑らかな線を描いているわけではなく、律儀な計算に基づいています。


 ベジエ曲線が描かれる仕組みを説明するために、「ド・カステリョのアルゴリズム」が、よく引き合いに出されます。これは以下のような考え方です。


 まず、ハンドルおよびハンドルの先端を結んだ線を、それぞれ、同じ比率で分割する点を取ります。次に、その点を結び、結んだ線を、再び同じ比率で分割します。さらに、その点を結び、結んだ線を同じ比率で分割すると、ベジエ曲線上の1点(P)が定まります。この比率を 0:1 から 1:0 まで、連続して変化させると、点 P の位置も連続して変化して、滑らかな曲線を描く、というカラクリです。


 ここで、0から1まで連続して変化する数 t を考え、分割比率を t : 1−t として分割点の座標を計算していくと、点 P の座標 (x(t), y(t)) は次の式で表されます。

 これが(3次)ベジエ曲線の式になります。2つの式で、上の図の1本の曲線を表しています。座標を決める元にした数 t はパラメータ(媒介変数)と呼ばれ、パラメータを使って表した曲線をパラメトリック曲線と呼びます。


 普通に Illustrator を使っていて、この式を解く機会は、ほとんどないと思いますが、たとえば、メニューから「アンカーポイントの追加」を実行した場合は、上の図で t = 0.5 (分割比率0.5:0.5)のときの点にアンカーが追加されるのだ、と考えると、なんとなく目安になるのではないでしょうか。


 ところで「3次ベジエ曲線」の「3次」ですが、上の図のように「割って割って割って」と3段階踏むので「3次」になります。TrueType フォントや Flash で使われている2次ベジエ曲線の場合は「割って割って」の2段階になります。2次ベジエ曲線ではアンカー2つに対してハンドル(制御点)は1つです。

円のハンドルの巻


 Illustrator の だ円ツールで円を描くと、アンカーが4つのパスが出来ます。このときのハンドルの長さの比率がわかっていると、スクリプトで円弧を描くときなんかに便利です。また、この比率は「角を丸くする」フィルタなどでも使われています。ハンドルの座標を知るには、適当に円を描いて保存したファイルの中のデータを覗く手もありますが、ここでは理屈で割り出してみます。


 この円のアンカー間の線(セグメント)を1つとってみると、ハンドルは左右対称形をしています。ハンドルが左右対称形の場合、パラメータ t = 0.5 のときの点は曲線の中点になります。これは、前回触れた何とかのアルゴリズムに照らしてみると直感的にも明らかでしょう。



 いま、原点を中心とした半径1の円を、だ円ツールで描いたとして、アンカーとハンドルの座標を図のように割り当ててみます。


 この曲線を円弧とするなら、パラメータ t = 0.5 のとき、曲線の中点( cos 45°、sin 45°)を通るようにするのが良さそうです。(ハンドルは左右対称形なので t = 0.5 のときに中点を通ります。)


 これらの事情を元にして、前回のベジエ曲線x(t) の式に、パラメータ t と各点の x 座標を代入すると、半径1の円を描いたときのハンドルの座標の値 a は次のように求められます。

 なお、このようにハンドル長を決めたベジエ曲線は、あくまで円を近似したもので、正円と比べると若干の誤差があります。計算してみたところ、ベジエ曲線上の点と原点との距離は、約 1.00000 〜 1.00027 の範囲になりました。より誤差を少なくするような制御点の取り方もあるはずですが、弧の中点と中心を結んだ距離が半径と一致する、としたほうが、何かと便利な気もします。


 また、このハンドル長の値は、約 0.5522847 になり、Google 検索すると円関係の定数としていくつか Hit します(詳細不明)。Illustrator CS で原点を中心に半径 1000pt の円を描いて、保存したファイルの中身を見ると、552.2852 という座標値になっていました。



 任意の中心角の円弧の場合も、上記と同様にしてハンドルの長さを求められます。


 アンカーとハンドルの座標を左の図のように割り当てて計算すると、 a は以下のような値になります。

分割の巻

 下の図の P 点のところを ペンツールでポチッと突付いてアンカーを追加、というのは、言い換えればベジエ曲線を P 点で分割する、ということをしています。分割されたそれぞれの曲線は新たなハンドルを伴っていますが、このハンドルの位置がどう決まるのかの話です。何でこんなこと考えるのかというと、たとえばスクリプトでパスにアンカーを追加するときは、この新たなハンドルの座標を算出して適切に指定してやる必要があるのです。


 いかにも面倒そうですが、実は意外と単純です。



 右の図は、「 数式で表すの巻 」で触れた、 t :1−t で分割して曲線上の点を決める仕組みの図です。一部が赤くなっていますが、この赤い線が、曲線上の点で分割した場合の新しいハンドルになります。実にシンプルというか合理的です。


 つまりハンドルの位置を割り出したいときは、制御点の間を t :1−t で分割していけばいいわけです。0≦t≦1 のとき、2点の間を t :1−t で分割する点の座標は下の図のようになります。これより、図の点 R の x 座標も、下のように求められます。

※ 2017.06.24 数式を修正しました。

接線の巻

 ベジエ曲線上のある点での接線の傾きを割り出したい場合には、「 曲線といえども接点の部分で ものすごく拡大して取り出して見るとほとんど直線だから、その直線の傾きを接線の傾きとすればいいじゃないか 」というような考え方をします。具体的には「 微分 」を使います。ビブンと聞いて拒絶反応が出る方でも、右下の図のような手順で計算すると x'(t) とやらが出るとだけ考えれば何とかなると思います。


「 数式で表すの巻 」で書いたベジエ曲線の式を、右のようなかんじで t について微分したものを x'(t)y'(t) とすると、

が、パラメータ t のときの曲線上の点での接線の傾きになります(分母が0のときの処理に注意)。


 逆に、傾き s の直線が接する曲線上の点は、

を t について解いて、その パラメータ t から曲線上の点を求めることで割り出せます。

長さの巻

 ベジエ曲線の長さを割り出すには「 積分 」を使います。


 上で接線の傾きを割り出す際には、曲線を細かい直線に分けましたが、その細かく分けたものを全部つなげると長さが割り出せるじゃないか、という考え方です。



 公式としては、右のようになります。底辺 x'(t) 、高さ y'(t) の極小三角形の斜辺の長さを求めて、それを全部足すというようなことをしています。


 公式から実際に長さを算出するには、数値積分の手法(台形法、シンプソン法、など)を用います。

ベジエ曲線の資料

 Don Lancaster's Guru's Lair Cubic Spline Library には、ベジエ曲線がらみの資料がたくさんあります。英語+数式+PDFという三重苦に耐えて読みますと、いろいろタメになりそうな雰囲気です。


 そういう私は、まだ ほとんど読んでないんですけど。中に、サインカーブの近似 という資料があったので、それを参考にしてサインカーブを描く JavaScript スクリプトを作ってみました。実行すると原点(デフォルトではアートボードの左下)付近に描きます。ちなみに数式部分をすっとばして結果の座標だけ拝借したため、どうやってどの程度 近似しているのかはわかりません。でもソレっぽいと思います。(※1)

download:→ http://shspage.com/aijs/


※1:〔追記〕これでは心もとないので、実際の sin の値による折れ線( x 座標の間隔= PI/100 )と重ねてみました。拡大すると若干のズレも確認できますが。ちょっとした図版に使うには十分に実用的ではないでしょうか。> sine_cmp.pdf


 以前「 数式で表すの巻 」で、特定のパラメータに対して曲線上の1点が決まる仕組みとして触れた「ド・カステリョのアルゴリズム」については、国内の複数のサイトを参考にしましたが、このサイトの "Bezier curve recursive midpoint rule"(ベジエ曲線 再帰中点法?)という資料で紹介されている方法は、それとは少し違っていて、制御点間の中点をどこまでもハンブンコハンブンコして曲線上の点を次々と導き出すということをしているようです。この描き方は 1959 年にポール・ド・カステリョが発見し、1960 年代にピエール・ベジエが CAD に応用したのだそうです。その簡潔さに基づく美しさから、本来の「ド・カステリョのアルゴリズム」は、こっちなんじゃないかと思わされますが、詳細はまだわかりません。


つづく。