So-net無料ブログ作成

太さの変わるBezier曲線の生成 - その21 [考え中 - 太さの変わるBezier曲線]

これからAGG方式のSmoothingアルゴリズムをNSBezierPathにカテゴリとして実装してみる。まずNSBezierPathの復習。

NSBezierPathのAGG方式によるSmoothing

MacOS XのCocoa環境でBeizer曲線を描くにはNSBezierPathを使う。これはPostScriptと、そしてpdfとほぼ同機能のBezier曲線が描ける。

折れ線のNSBezierPathをAGG方式でSmoothingするメソッドを実装することを考えてみる。 たとえば

        float *x, *y;
        path = [NSBezierPath bezierPath];
        ......// pathの生成
        [path smoothingWithKValue:1.0f];  // Smoothing
        [path stroke];  // pathの描画
        ......
のような感じにする。このsmoothingWithKValue:メソッドがもとのNSBezierPathの持っていた端点は動かさずにAGG方式で新しい中間の制御点を追加してSmoothingする。

もとのpathが中間の制御点を持っていた場合、それは無視することにする。

NSBezierPath

NSBezierPathの基本

NSBezierPathは

  1. 空のpathを作る
  2. 描きはじめの点に移動する
  3. 次の点を指定してそこまで線を引く
  4. それを繰り返す
  5. 必要な場合には閉じる
というふうに手で描くようにBezier曲線を描画する。これはPostScript(そしてpdf)と全く同じ描画モデルであって、MacOS Xの描画機能であるQuartzはpdfのサブセットをベースにしているので当然といえば当然(そして先祖をたどればNeXTのDisplay Postscriptにたどりつく)。具体的には
        float *x, *y;
        path = [NSBezierPath bezierPath];
        [path moveToPoint:NSMakePoint(x[0], y[0])];
        [path lineToPoint:NSMakePoint(x[1], y[1])];
        [path lineToPoint:NSMakePoint(x[2], y[2])];
        [path closePath];
など読んで字のごとしとなる。

ただし、このままでは線は表示されない。実際の描画は表示用のNSViewなどの-drawRect:メソッドの中やNSImageにFocusをあてて

      [path stroke];
などとすることで実際に線が見える形で描かれる。逆に表示すべきNSViewがない段階でも線のデータを作っておけるので、同じものを繰り返し描画する必要がある場合(動画の上にPathを引く場合など)はstrokeだけを繰り返し呼べばよい。

線を引くメソッド

曲線を描くためのメソッドが多く定義されているが、

- (void)moveToPoint:(NSPoint)aPoint;
- (void)lineToPoint:(NSPoint)aPoint;
- (void)curveToPoint:(NSPoint)aPoint
       controlPoint1:(NSPoint)controlPoint1
       controlPoint2:(NSPoint)controlPoint2;
- (void)closePath;
が基本的なメソッドである。それぞれ
  1. 描きはじめの位置にペンを移動する
  2. 指定した位置まで直線を引く
  3. 指定した位置まで曲線を描く
  4. 閉じる
を行う。

サブパスとその作り方

ちょっと問題なのは(PostScriptやpdfのBezier曲線と同じように)NSBezierPathにはサブパスの概念がある。サブパスとはひとつの曲線がそれぞれは繋がっていないいくつかの部分に分けることができるというものである。

人が線を引く場合に、一筆描きできない曲線はいったん筆を紙から離して別の点へ移動させ、またそこから描き始めるが、NSBezierPathにもそういうことができるようになっている。

そのためには途中で移動のためのメソッドを呼んでやればよい。具体的には

        float *x, *y;
        path = [NSBezierPath bezierPath];
        [path moveToPoint:NSMakePoint(x[0], y[0])]; // (1)
        [path lineToPoint:NSMakePoint(x[1], y[1])];
        [path moveToPoint:NSMakePoint(x[2], y[2])];  // (2)
        [path lineToPoint:NSMakePoint(x[3], y[3])];
        [path closePath];
などとなる。 ここで(1)から始まる線と(2)から始まる線は見た目二つに分かれるが、NSBezierPathのオブジェクトとしてはひとつのものである。

そしてひとつのサブパスの描画の最後にclosePathメソッドを呼んでやれば、サブパスごとに曲線を閉じることができる。ただし、サブパスごとに線幅や描画色を変えることはできない。

これは複雑な曲線をひとまとめにできる便利な機能であるが、与えられた曲線に手を加えようとするときには面倒なことが起こる。

その面倒をどうするか、の前にNSBezierPathのエレメントについて、次回。


nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0