Draw ellipse with start and end angle in Objective

I am writing an iPad app in which I am rendering XML objects that represent shapes into graphics on the screen. One of the objects I am trying to render is arcs. Essentially these arcs provide me with a bounding rectangle as well as a start and end angle.

Given attributes:

  • x
  • y
  • width
  • height
  • startAngle
  • endAngle
  • With these values I need to draw the arc (which is essentially part of an ellipse). I can not use the following:

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

    because it draws a full ellipse. Basically I need the above but it needs to take into account the start and end angles so only part of the ellipse is displayed. I am thinking this will involve either drawing a cubic Bezier curve or a quadratic Bezier curve. The problem is I have no clue how to calculate the start point, end point, or control points with the information I am given.


    You can probably achieve what you want by setting up a clip path around the drawing of the ellipse.

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

    The exact radius for the clipping isn't important. It needs to be big enough so it only clips the ellipse at the ends, not through the desired arc.


    这个类别将有所帮助。

    #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
    

    You will have to use addQuadCurveToPoint:controlPoint: instead of bezierPathWithOvalInRect.

    The method definition is as:-

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

    that is CGPoint are the arguments(input) for both the parameters.

    You will also have to set the start point using moveToPoint: before calling addQuadCurveToPoint which will act as current point(As you can see their's no start point as parameter in the method).

    In your case you will have

    1>x,y as your starting point

    2>x+width and y+height as endpoint

    you don't need angles here or you can implement your logic to use the angles.Am uploading an image to make thing clear.

    这是描述起点,终点和控制点的图像

    链接地址: http://www.djcxy.com/p/61682.html

    上一篇: 使用贝塞尔曲线绘制螺旋

    下一篇: 在Objective中绘制具有开始和结束角度的椭圆