SSブログ

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

今日もまた送別会があった。今日は初めて僕より年上。こないだのことがあったのでもったいないけどあまり飲まずにかえってきた。来月すぐまたある。しかしこう送別会が続くと出費がかさんで苦しい。

さて、AGG方式のSmoothingのNSBezierPathのカテゴリとしての実装の続き。今回はアルゴリズムそのものの実装。

Smoothingの中間点位置の計算

それでは具体的にAGG方式で制御点の位置を計算するメソッドgetControlPoints:WithAnchors:andKValue:。これは、端点座標保持用のクラスDCAnchorsOfSubPathのプライベートメソッド。

typedef NSPoint DCVector;
static float    distanceBetween(NSPoint *p0, NSPoint *p1);
static DCVector vector(NSPoint *to, NSPoint *from);
static NSPoint  addVectorToPoint(NSPoint *pos, DCVector *vector);
static DCVector scalarMultOfVector(DCVector *vector, float scalar);

- (void)getControlPoints:(NSPointArray)controls
             WithAnchors:(NSPointArray)points
               andKValue:(float)kvalue
{
    float   lneg = distanceBetween(points, points + 1);
    float   lpos = distanceBetween(points + 1, points + 2);
    if ((lneg <= 0.0f) || (lpos <= 0.0f)
        || NSEqualPoints(points[0], points[2])) {   // (1)
        controls[0] = points[1];
        controls[1] = points[1];
        return;
    }
    else {
        float   leng = lneg + lpos;
        float   alphaneg = kvalue * lneg / leng;
        float   alphapos = kvalue * lpos / leng;
        DCVector difvec = vector(points, points + 2);
        DCVector negvec = scalarMultOfVector(&difvec, alphaneg * 0.5f);
        DCVector posvec = scalarMultOfVector(&difvec, -alphapos * 0.5f);
        controls[0] = addVectorToPoint(points + 1, &negvec);
        controls[1] = addVectorToPoint(points + 1, &posvec);
    }
}
最初のいくつかのC関数は2次元のベクトル演算のための関数である。うっかりNSPointへのポインタを引数に受ける関数を書いてしまって、NSEqualPoints()と一貫性がなくなってしまった。美しくないけど、間違えばコンパイラが教えてくれるので修正は後回しにする。

まず最初に制御点間の距離を計算して、少なくとも一方の距離が0、あるいは両側の端点が一致している場合はAGG方式ではSmoothingできないので中間制御点を端点に一致させて終わる。

それ以外の場合、Smoothingが可能なので式-95に従って計算しているだけである。

本当は両側の端点が一致している場合だけ排除すればいいのだけど、距離0の場合はSmoothingにならない(微係数が連続にならない)のでやるだけ無駄で、計算量を減らすためにこうしている。さらには、サブパスの端点を取り出すときに同一座標のの端点が連続するときは1点に集約するか、逆に同じ座標を繰り返すところではSmoothingされないので例えばハート型のしっぽのような点を含めたい場合はそうすればよい。どうするかはSmoothingの仕様による、ということになる。

制御点を使って曲線を引く

計算した制御点を使って曲線を描き直すメソッド、appendSubPathTo:WithControls:は

- (void)appendSubPathTo:(NSBezierPath *)path
           WithControls:(NSPoint *)controls
{
    int count = [anchors count];
    int c;
    [path moveToPoint:[[anchors objectAtIndex:0] pointValue]];
    for (c = 0 ; c < count - 1 ; c ++)
        [path curveToPoint:[[anchors objectAtIndex:c + 1] pointValue]
             controlPoint1:controls[2 * c]
             controlPoint2:controls[2 * c + 1]];
    if (isClosed)
        [path closePath];
}
これも簡単。curveTo~メソッドで順番に描いていくだけ。

これで実装は全部おしまい。実際に動作させたらどうなるか、次に見る。


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

nice! 0

コメント 0

コメントを書く

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

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。