13

iOSアプリケーションで、一連の特定のポイントを通過するベジェ曲線を描画する最良の方法は何ですか?

4

6 に答える 6

7

もう少し一般的な方法は、たとえば、BEMSimpleLineGraph GitHub プロジェクトを参照することで実現できます(詳細については、こちらを参照してください: )。ここでは、指定された点のリストを介してベジエ曲線を描く方法を抽出しました。

ヘッダー ファイル (BezierLine.h):

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <CoreGraphics/CoreGraphics.h>

@interface BezierLine : NSObject

/*
 Draws a bezier curved line on the given context
 with points: Array of CGPoint values
 */
-(void) drawBezierCurveInContext:(CGContextRef)context withPoints:(NSArray*)points lineColor:(UIColor*)color lineWidth:(CGFloat)lineWidth;

@end

実装 (BezierLine.m):

#import "BezierLine.h"

@implementation BezierLine

-(void) drawBezierCurveInContext:(CGContextRef)context withPoints:(NSArray*)points lineColor:(UIColor*)color lineWidth:(CGFloat)lineWidth {
    if (points.count < 2) return;

    CGPoint CP1;
    CGPoint CP2;

    // LINE
    UIBezierPath *line = [UIBezierPath bezierPath];

    CGPoint p0;
    CGPoint p1;
    CGPoint p2;
    CGPoint p3;
    CGFloat tensionBezier1 = 0.3;
    CGFloat tensionBezier2 = 0.3;

    CGPoint previousPoint1;
    CGPoint previousPoint2;

    [line moveToPoint:[[points objectAtIndex:0] CGPointValue]];

    for (int i = 0; i < points.count - 1; i++) {
        p1 = [[points objectAtIndex:i] CGPointValue];
        p2 = [[points objectAtIndex:i + 1] CGPointValue];

        const CGFloat maxTension = 1.0f / 3.0f;
        tensionBezier1 = maxTension;
        tensionBezier2 = maxTension;

        if (i > 0) { // Exception for first line because there is no previous point
            p0 = previousPoint1;
            if (p2.y - p1.y == p1.y - p0.y) tensionBezier1 = 0;
        } else {
            tensionBezier1 = 0;
            p0 = p1;
        }

        if (i < points.count - 2) { // Exception for last line because there is no next point
            p3 = [[points objectAtIndex:i + 2] CGPointValue];
            if (p3.y - p2.y == p2.y - p1.y) tensionBezier2 = 0;
        } else {
            p3 = p2;
            tensionBezier2 = 0;
        }

        // The tension should never exceed 0.3
        if (tensionBezier1 > maxTension) tensionBezier1 = maxTension;
        if (tensionBezier2 > maxTension) tensionBezier2 = maxTension;

        // First control point
        CP1 = CGPointMake(p1.x + (p2.x - p1.x)/3,
                          p1.y - (p1.y - p2.y)/3 - (p0.y - p1.y)*tensionBezier1);

        // Second control point
        CP2 = CGPointMake(p1.x + 2*(p2.x - p1.x)/3,
                          (p1.y - 2*(p1.y - p2.y)/3) + (p2.y - p3.y)*tensionBezier2);


        [line addCurveToPoint:p2 controlPoint1:CP1 controlPoint2:CP2];

        previousPoint1 = p1;
        previousPoint2 = p2;
    }

    CGContextSetAllowsAntialiasing(context, YES);
    CGContextSetStrokeColorWithColor(context, color.CGColor);
    CGContextSetLineWidth(context, lineWidth);
    CGContextAddPath(context, line.CGPath);
    CGContextDrawPath(context, kCGPathStroke);
}


@end

たとえば、UIGraphicsBeginImageContext を使用して画像コンテキストを作成し、UIGraphicsGetCurrentContext() でコンテキストを取得することで使用できます。

それ以外の場合は、コードを変更して結果のパスを CALayer に割り当て、それを UIView に追加することができます。

お役に立てれば。

于 2015-04-26T10:19:36.983 に答える
4

これは遅いかもしれませんが、正しい答えを探している人のためだけです. addLineToPoint を使用して直線を描画する代わりに。addCurveToPoint を使用して曲線を描くことができます。例えば

[bezierPath moveToPoint:CGPointMake(0, 0)];
[bezierPath addCurveToPoint:CGPointMake(40, 100) 
              controlPoint1:CGPointMake(20, 0) 
              controlPoint2:CGPointMake(20, 100)];
[bezierPath addCurveToPoint:CGPointMake(80, 50) 
              controlPoint1:CGPointMake(60, 100) 
              controlPoint2:CGPointMake(60, 50)];

// and you may don't want to close the path
// [bezierPath closePath];

曲線の制御点を選択するのは、実際にはあなた次第です。x = last_point_x + 20; を使用するだけです。y = コントロール ポイント 1 の last_point_y、および x = current_point_x - 20; y = current_point_y;

曲線のセグメント幅が異なる場合があるため、20 の代わりに他の値を使用することもできます。

于 2014-01-09T22:02:46.883 に答える
2

ウェブ上でベジエ曲線を作成する方法の例を簡単にググることができます。例として、この短いtutを見つけました。

たとえば、次のコード スニペットを使用して、近いベジエ曲線を作成できます。

UIBezierPath* path = [UIBezierPath bezierPath];

[path moveToPoint:pt1];
[path addLineToPoint:pt2];
[path addLineToPoint:pt3];

[path closePath];

出発点として役立つことを願っています。

于 2012-10-15T22:20:36.383 に答える
0

CGPointFromString次の方法を使用すると、はるかに効率的になります。

 NSArray *pointArray = @[@"{3.0,2.5}",@"{100.0,30.2}", @"{100.0,200.0}", @"{3.0,200.0}"];

// draw the path
UIBezierPath *aPath = [UIBezierPath bezierPath];
for (NSString *pointString in pointArray) {
    if ([pointArray indexOfObject:pointString] == 0)
        [aPath moveToPoint:CGPointFromString(pointString)];
    else
        [aPath addLineToPoint:CGPointFromString(pointString)];
}
[aPath closePath];
于 2014-07-24T14:41:09.863 に答える
-1
UIBezierPath *aPath = [UIBezierPath bezierPath];

// Set the starting point of the shape.
[aPath moveToPoint:CGPointMake(100.0, 0.0)];

// Draw the lines.
[aPath addLineToPoint:CGPointMake(200.0, 40.0)];
[aPath addLineToPoint:CGPointMake(160, 140)];
[aPath addLineToPoint:CGPointMake(40.0, 140)];
[aPath addLineToPoint:CGPointMake(0.0, 40.0)];
[aPath closePath];
于 2012-12-05T07:17:33.767 に答える