8

形状を表す XML オブジェクトを画面上のグラフィックスにレンダリングする iPad アプリを作成しています。レンダリングしようとしているオブジェクトの 1 つは円弧です。基本的に、これらの円弧は、開始角度と終了角度だけでなく、外接する四角形も提供します。

与えられた属性:

  • バツ
  • y
  • 身長
  • 開始角度
  • 終了角度

これらの値を使用して、円弧を描く必要があります (これは本質的に楕円の一部です)。以下は使えません。

    UIBezierPath *arc = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(x, y, width, height)];
    [UIColor blackColor] setStroke];
    [arc stroke];

完全な楕円を描くからです。基本的には上記が必要ですが、開始角度と終了角度を考慮する必要があるため、楕円の一部のみが表示されます。これには、3 次ベジエ曲線または 2 次ベジエ曲線の描画が含まれると考えています。問題は、与えられた情報を使用して開始点、終了点、または制御点を計算する方法がわからないことです。

4

3 に答える 3

10

楕円の描画の周りにクリップ パスを設定することで、おそらく目的を達成できます。

CGContextSaveGState(theCGContext);
CGPoint center = CGPointMake(x + width / 2.0, y + height / 2.0);
UIBezierPath* clip = [UIBezierPath bezierPathWithArcCenter:center
                                                    radius:max(width, height)
                                                startAngle:startAngle
                                                  endAngle:endAngle
                                                 clockwise:YES];
[clip addLineToPoint:center];
[clip closePath];
[clip addClip];

UIBezierPath *arc = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(x, y, width, height)];
[[UIColor blackColor] setStroke];
[arc stroke];

CGContextRestoreGState(theCGContext);

クリッピングの正確な半径は重要ではありません。必要な円弧を通過するのではなく、端で楕円をクリップするだけの十分な大きさが必要です。

于 2012-05-17T22:05:38.170 に答える
4

このカテゴリは役に立ちます。

#import <Foundation/Foundation.h>

@interface UIBezierPath (OvalSegment)

+ (UIBezierPath *)bezierPathWithOvalInRect:(CGRect)rect startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle;
+ (UIBezierPath *)bezierPathWithOvalInRect:(CGRect)rect startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle angleStep:(CGFloat)angleStep;

@end

#import "UIBezierPath+OvalSegment.h"

@implementation UIBezierPath (OvalSegment)

+ (UIBezierPath *)bezierPathWithOvalInRect:(CGRect)rect startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle angleStep:(CGFloat)angleStep {
    CGPoint center = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
    CGFloat xRadius = CGRectGetWidth(rect)/2.0f;
    CGFloat yRadius = CGRectGetHeight(rect)/2.0f;

    UIBezierPath *ellipseSegment = [UIBezierPath new];

    CGPoint firstEllipsePoint = [self ellipsePointForAngle:startAngle withCenter:center xRadius:xRadius yRadius:yRadius];
    [ellipseSegment moveToPoint:firstEllipsePoint];

    for (CGFloat angle = startAngle + angleStep; angle < endAngle; angle += angleStep) {
        CGPoint ellipsePoint = [self ellipsePointForAngle:angle withCenter:center xRadius:xRadius yRadius:yRadius];
        [ellipseSegment addLineToPoint:ellipsePoint];
    }

    CGPoint lastEllipsePoint = [self ellipsePointForAngle:endAngle withCenter:center xRadius:xRadius yRadius:yRadius];
    [ellipseSegment addLineToPoint:lastEllipsePoint];

    return ellipseSegment;
}

+ (UIBezierPath *)bezierPathWithOvalInRect:(CGRect)rect startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle {
    return [UIBezierPath bezierPathWithOvalInRect:rect startAngle:startAngle endAngle:endAngle angleStep:M_PI/20.0f];
}

+ (CGPoint)ellipsePointForAngle:(CGFloat)angle withCenter:(CGPoint)center xRadius:(CGFloat)xRadius yRadius:(CGFloat)yRadius {
    CGFloat x = center.x + xRadius * cosf(angle);
    CGFloat y = center.y - yRadius * sinf(angle);
    return CGPointMake(x, y);
}

@end
于 2015-05-13T20:06:54.683 に答える
2

addQuadCurveToPoint:controlPoint:代わりに使用する必要がありますbezierPathWithOvalInRect.

メソッドの定義は次のとおりです。

- (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint

つまり、CGPoint は両方のパラメーターの引数 (入力) です。

moveToPoint:また、現在のポイントとして機能する呼び出しの前に使用して開始点を設定するaddQuadCurveToPoint必要があります(メソッドのパラメーターとして開始点がないことがわかります)。

あなたの場合、あなたは持っているでしょう

1>x,y を出発点として

端点としての 2>x+width および y+height

ここで角度は必要ありません。または、角度を使用するロジックを実装できます。明確にするために画像をアップロードしています。

これは、始点、終点、および制御点を説明する画像です

于 2012-05-17T21:57:46.517 に答える