2012-05-17 37 views
5

シェイプを表すXMLオブジェクトを画面上のグラフィックスにレンダリングするiPadアプリケーションを作成しています。レンダリングしようとしているオブジェクトの1つが円弧です。基本的にこれらの弧は、境界矩形と開始角度と終了角度を私に提供します。Objective-Cで開始角度と終了角度の楕円を描く

考えると属性:私は弧を描く必要があり、これらの値で

  • X
  • Y
  • 高さ
  • startAngleの
  • endAngle

(本質的に楕円の一部である)。次のように使用することはできません:

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

完全な楕円を描くので、私は次のものを使用できません。基本的に私は上記を必要としますが、開始角度と終了角度を考慮に入れる必要がありますので、楕円の一部のみが表示されます。これは、3次ベジェ曲線または2次ベジェ曲線を描くことを含むと考えています。問題は、私が与えられた情報で始点、終点、または制御点をどのように計算するかの手がかりがないことです。

答えて

9

おそらく、楕円の描画の周りにクリップパスを設定することにより、あなたが望むものを達成することができます。

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); 

クリッピングの正確な半径は重要ではありません。それは、必要な円弧ではなく、端の楕円のみをクリップするように十分大きくなければなりません。

+0

おかげさまで、魅力的なように働きました(Objective-Cや描画グラフィックスはまだまだ新しくなりました)。 –

2

あなたが代わりにbezierPathWithOvalInRect.

addQuadCurveToPoint:controlPoint:を使用する必要がありますメソッドの定義がようである: -

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

するCGPointでそのパラメータの両方の引数(入力)されています。

addQuadCurveToPointを呼び出す前に、開始ポイントを設定する必要があります。このポイントは、現在のポイントとして機能します(メソッドの開始ポイントが表示されないため)。あなたのケースでは

あなたは

1>のx、あなたの出発点として、Y

エンドポイント

として2> X +幅とy +高さを持つことになりますが、ここで角度を必要としませんかangle.Amを使用してロジックを実装して、イメージをアップロードして明確にすることができます。

Here is the image describing the start point,end point and control point

+0

2次ベジェ曲線はしません。たぶん、キュービックベジェ曲線の制御点を計算して、与えられたプロパティで楕円が描かれるようにすることができます。与えられた情報をベジェ曲線に変換するのに必要な数学がなければ、これは問題に答えません。 – thundersteele

+0

実際には、パスを明示的に描画したい場合(すなわち、クリッピングなしで)、エリプスのパラメトリック方程式が必要です。それで、あなたは、楕円を近似する短いセグメント(二次的または立方体的、または線形的)の束を作らなければならないでしょう。クリッピングは良いです。 – samson

+1

これは素晴らしいTechotopiaです: http://www.techotopia.com/index.php/An_iPhone_Graphics_Drawing_Tutorial_using_Quartz_2D#Drawing_an_Ellipse_or_Circleここ – Aardvark

3

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

#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 
+0

すばらしいカテゴリ!!!それを完璧にするために、行を追加する最初のポイントは、上記のコードのfirstEllipsePointである開始ポイントを含むべきではありません。だから 'for'ステートメントは' for(CGFloat angle = startAngle + angleStep; angle

+0

@RungeZhai:true、done! – kanobius

+0

ellipsePointForAngleが正しくないか、または私が使用している方法と異なる矛盾があります。楕円の周りで角度が増加するにつれて、それはわずかに前後にオフセットするように見える。これは、楕円の幅と高さを含まないことによって部分的に発生します。これは重要な点であり、角度から円上の点を見つけることとは異なります。 – VagueExplanation