2011年7月1日金曜日

Flex/Flashでマウスで滑らかな曲線を描くには?

フツーにlineTo

Flexでマウスで線を描くにはフツーはこういう風にするだろう。

var gfx:Graphics = canvas.graphics;
gfx.moveTo(prevPos.x, prevPos.y);
gfx.lineTo(currPos.x, currPos.y);

曲線を描くには、この直線を細かく分割して曲げていけば良い。マウスイベントを連続的に直線の開始点と終了点に割り当てれば、まぁそれなりの曲線を描くことはできる。

しかし、そのクオリティーはこの程度だ。


やはり、ガクガクしているし、直線的な部分が見られる。これでもアプリケーションによっては十分かもしれないけれど、今回はもっと滑らかに曲線を描きたい。


スプライン曲線はどう?

次はこちらのページを参考にスプライン曲線でやってみた。
Flashゲーム講座&ASサンプル集【曲線について】


さらにガタガタに(^^); 使ったアルゴリズムは分割数を指定しなければならず、そのせいもあってポイント多すぎるのが原因だと思う。

マウスイベントを間引いて、さらに分割数をある程度少なくすればキレイになるかと色々試してみたけれど、大してキレイにならなかった。

結局、描画にlineToを使っているので、分割数が少なくなるとガタガタ度合いは増えていくのだ。


Inkscapeの描画アルゴリズムはどう?

もう少しいい方法は無いかと思って色々と探すと、Inkscapeの描画アルゴリズムを使っているというJavaScriptのサンプルを見つけた。
フリーハンドでベジェ曲線を描く

この滑らかさは素晴らしい。このJSのコードをASに変換されている方もいらしたので、移植すればFlexでも使えるだろう。
JavaScriptとActionScriptは兄弟か? - flashrod

しかし、まずコードがGPLであること。そして描画中に線がウネウネするのが気に入らず、さらに違う方法を考えることにした。


curveToをうまく使えばいいのでは?

GraphicsクラスにはlineToの他にcurveToというメソッドもある。これは曲線を描くための専用メソッドで、開始点、終了点、制御点を与えてやる必要がある。これを上手く使えば、よりキレイな曲線を描けるはずだ。

しかし、問題はその制御点をどう計算するかだ。色々と考えながら調べていると、こんなサンプルを見つけた。







This is IT. しかも非常に短いコード。ポイントはここだ。

gfx.curveTo(prevPos.x, prevPos.y, (currPos.x + prevPos.x)/2, (currPos.y + prevPos.y)/2);

このように、非常に簡単に制御点を計算できる。その結果このようになった。


一番始めよりはよっぽどマシな曲線になっている。

しかし、まだまだ改善の余地がある。ポイントの数を上手く間引けば、さらにキレイな曲線が描けるようになるはずだ。


単純にポイントを1/4に間引いてみる

とりあえず、何も考えずにポイントを1/4に間引いてみた。すると、さっきよりもさらにキレイになった。


しかし、単純に間引くだけでは重要なポイントまでもが間引かれてしまう場合があり、その結果、形状が大きく変わってしまうことがあるとわかった。

さて、その「重要なポイント」をどう判断するか・・・・とりあえず、ここまで。