16

cocoaアプリケーションでcurveToPoint:controlPoint1:controlPoint2:を使用して作成された完全に通常の4点ベジェ曲線(2点と2つの制御点)があるとします。

単純な3次ベジェ曲線の例
曲線に沿って、どのようにして点(および接線)を見つけますか?


後で:以下のMichalの回答に基づく完全で単純化されたソリューションについては、次をクリックしてください:
3次ベジェ曲線上の点の接線を見つける(iPhoneの場合)

そして、 https://stackoverflow.com/a/31317254/294884からコードをコピーして貼り付けるだけです

4

4 に答える 4

31

位置の計算の背後にはいくつかの簡単な計算があります。ウィキペディアでも、ベジェ曲線について説明しているすべての論文でそれについて読むことができます。とにかく、実際にコードで実装するのに苦労しているすべての人に関係することができるので、このサンプルUIViewを作成しました。これは、おそらく最も簡単な方法であるためです。

#import "MBBezierView.h"

CGFloat bezierInterpolation(CGFloat t, CGFloat a, CGFloat b, CGFloat c, CGFloat d) {
    CGFloat t2 = t * t;
    CGFloat t3 = t2 * t;
    return a + (-a * 3 + t * (3 * a - a * t)) * t
    + (3 * b + t * (-6 * b + b * 3 * t)) * t
    + (c * 3 - c * 3 * t) * t2
    + d * t3;
}

@implementation MBBezierView

- (void)drawRect:(CGRect)rect {
    CGPoint p1, p2, p3, p4;
    p1 = CGPointMake(30, rect.size.height * 0.33);
    p2 = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
    p3 = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect));
    p4 = CGPointMake(-30 + CGRectGetMaxX(rect), rect.size.height * 0.66);

    [[UIColor blackColor] set];
    [[UIBezierPath bezierPathWithRect:rect] fill];

    [[UIColor redColor] setStroke];

    UIBezierPath *bezierPath = [[[UIBezierPath alloc] init] autorelease];   
    [bezierPath moveToPoint:p1];
    [bezierPath addCurveToPoint:p4 controlPoint1:p2 controlPoint2:p3];
    [bezierPath stroke];

    [[UIColor brownColor] setStroke];
    for (CGFloat t = 0.0; t <= 1.00001; t += 0.05) {
        CGPoint point = CGPointMake(bezierInterpolation(t, p1.x, p2.x, p3.x, p4.x), bezierInterpolation(t, p1.y, p2.y, p3.y, p4.y));
        UIBezierPath *pointPath = [UIBezierPath bezierPathWithArcCenter:point radius:5 startAngle:0 endAngle:2*M_PI clockwise:YES];
        [pointPath stroke];
    }   
}

@end

これは私が得るものです:

代替テキスト

于 2010-10-30T19:49:00.953 に答える
3

tがMichalが提案している曲線に沿った距離であるという近似は、いくつかの曲線や目的によっては厄介な場合があります。悲しいことに、私はかなり長い間運が悪かったので、正しいソリューションのObj-C実装を探してきました。

ただし、このソリューションは、Mike"Pomax"Kamermansがベジェ曲線のすばらしい入門書でかなり素晴らしい方法で説明しています。それは、処理とパブリックドメインで書かれたすべてのコードさえ持っています。まだ誰もこれをObj-Cに変換していないことに驚いています。とても魅力的です、私はそうです。

于 2014-04-10T19:16:36.523 に答える
0

ベジェ曲線は、ベクトル係数または複素係数を持つ多項式関数として簡単に表示できます。次に、スクリーンショットのような3次ベジェ曲線が3次の多項式関数によって生成され、曲線上の各点は、特定の入力値tに対して評価された曲線多項式の結果B(t)を表します。私が間違っていなければ、曲線の作成に使用される多項式がわかれば、B(t)= a + biについて簡単に解くことができます。ここで、a + biは、 tを求めたい複素平面上の点を表します。の値。このような多項式の根を見つけることはよく理解されている問題であり、2次以下の曲線では代数的に解くことができ、高次の多項式ではフォワードニュートンなどの方法を使用できます。生成する多項式がわかっている場合は、もちろん導関数を見つけるのも非常に簡単です。ベジェ曲線は通常、別の曲線が描画されたときに係数のみが変更される「テンプレート多項式」から描画されるため、ドキュメントのどこかで調べることができます。

于 2010-11-24T11:34:21.407 に答える
0

Michalの答えに基づいて、私のプロジェクトのためにSwiftでこれを書きました。たぶん役立つでしょう、元のFattieのスクリーンショットの説明とともにここに残してください:

let targetPoint = CGPoint(x: bezierInterpolation(t: distance, p1: sP1.point.x, cp1: sP1.nextMarker.x, cp2: sP2.previousMarker.x, p2: sP2.point.x),
                          y: bezierInterpolation(t: distance, p1: sP1.point.y, cp1: sP1.nextMarker.y, cp2: sP2.previousMarker.y, p2: sP2.point.y))

func bezierInterpolation(t: CGFloat, p1: CGFloat, cp1: CGFloat, cp2: CGFloat, p2: CGFloat) -> CGFloat {
    let t2: CGFloat = t * t;
    let t3: CGFloat = t2 * t;
    return p1 + (-p1 * 3 + t * (3 * p1 - p1 * t)) * t
    + (3 * cp1 + t * (-6 * cp1 + cp1 * 3 * t)) * t
    + (cp2 * 3 - cp2 * 3 * t) * t2
    + p2 * t3;
}

ここに画像の説明を入力してください

于 2021-01-07T09:18:08.953 に答える