首页 文章

在Objective-C中绘制具有起始和结束角度的椭圆

提问于
浏览
7

我正在编写一个iPad应用程序,我在其中渲染表示形状的XML对象到屏幕上的图形 . 我试图渲染的对象之一是弧 . 基本上这些弧为我提供了一个边界矩形以及一个开始和结束角度 .

给定属性:

  • x

  • y

  • 宽度

  • 身高

  • startAngle

  • endAngle

使用这些值,我需要绘制弧(基本上是椭圆的一部分) . 我不能使用以下内容:

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

因为它绘制了一个完整的椭圆 . 基本上我需要上面但是它需要考虑开始和结束角度,因此只显示椭圆的一部分 . 我认为这将涉及绘制三次贝塞尔曲线或二次贝塞尔曲线 . 问题是我不知道如何用我给出的信息计算起点,终点或控制点 .

3 回答

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

    裁剪的确切半径并不重要 . 它需要足够大,以便它只在末端夹住椭圆,而不是通过所需的弧 .

  • 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
    
  • 2

    您将不得不使用 addQuadCurveToPoint:controlPoint: 而不是 bezierPathWithOvalInRect.

    方法定义如下: -

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

    即CGPoint是两个参数的参数(输入) .

    您还必须在调用 addQuadCurveToPoint 之前使用 moveToPoint: 设置起点,该点将充当当前点(因为您可以看到它们的无起点作为方法中的参数) .

    在你的情况下,你会有

    1> x,y作为起点

    2> x宽度和y高度作为 endpoints

    你不需要这里的角度,或者你可以实现你的逻辑来使用角度 . 上传图像以使事情清楚 .

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

相关问题