2012-05-17 14 views
5

Я пишу iPad-приложение, в котором я передаю XML-объекты, которые представляют фигуры в графику на экране. Один из объектов, которые я пытаюсь сделать, - это дуги. По сути, эти дуги предоставляют мне ограничивающий прямоугольник, а также угол начала и конца.Рисование эллипса с начальным и конечным углом в Objective-C

Указанные атрибуты:

  • х
  • у
  • ширина
  • высота
  • StartAngle
  • endAngle

С этими значениями, мне нужно нарисовать дугу (который по существу является частью эллипса). Я не могу использовать следующее:

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

потому что он рисует полный эллипс. В основном мне нужно выше, но он должен учитывать начальный и конечный углы, поэтому отображается только часть эллипса. Я думаю, что это будет включать либо рисование кубической кривой Безье, либо квадратичную кривую Безье. Проблема в том, что я не знаю, как рассчитать начальную точку, конечную точку или контрольные точки с информацией, которую я даю.

ответ

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

Вы должны будете использовать addQuadCurveToPoint:controlPoint: вместо bezierPathWithOvalInRect.

определение метода как: -

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

что CGPoint аргументы (входные) для обоих параметров.

Перед тем, как позвонить addQuadCurveToPoint, вы должны установить стартовую точку с помощью moveToPoint:, которая будет действовать как текущая точка (поскольку вы можете видеть, что их начальная точка не является параметром в методе).

В вашем случае у вас будет

1> х, у в качестве отправной точки

2> х + ширина и у + высота в качестве конечной точки

вам не нужны углы здесь или вы можете реализовать свою логику для использования углов. Выгружаете изображение, чтобы все было ясно.

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

+0

Квадратичная кривая Безье не будет работать. Возможно, вы можете вычислить контрольные точки для кубической кривой безье, чтобы эллипс рисовался с заданными свойствами.Без математики, необходимой для перевода данной информации в кривую Безье, это не отвечает на вопрос. – thundersteele

+0

На самом деле, я думаю, что если вы хотите явно нарисовать путь (т. Е. НЕ с отсечением), вам понадобится параметрическое уравнение для elipse. Затем вам нужно будет создать кучу коротких сегментов (квадратичных или кубических или даже линейных), которые APPROXIMATE elipse. Обрезание лучше. – 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' должно быть' для (CGFloat angle = startAngle + angleStep; angle

+0

@RungeZhai: это правда, сделано! – kanobius

+0

ellipsePointForAngle кажется неправильным, или существует несоответствие, которое отличается для метода, который я использую. Поскольку угол увеличивается вокруг овала, он выглядит слегка смещенным вперед и назад. Это частично вызвано отсутствием ширины и высоты эллипса, что важно и отличается от того, как просто найти точку на круге под углом. – VagueExplanation