2012-05-17 10 views
5

Piszę aplikację na iPada, w której renderuję obiekty XML reprezentujące kształty w grafice na ekranie. Jednym z obiektów, które próbuję renderować, są łuki. Zasadniczo te łuki zapewniają mi prostokąt obwiedniowy, a także kąt początkowy i końcowy.Rysuj elipsę z początkowym i końcowym kątem w Objective-C

Podane atrybuty:

  • x
  • y
  • szerokość
  • wysokość
  • startAngle
  • endAngle

Tymi wartościami muszę narysować łuk (który jest w istocie częścią elipsy). Nie mogę użyć następującego:

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

ponieważ rysuje pełną elipsę. Zasadniczo potrzebuję powyższego, ale musi wziąć pod uwagę kąt początkowy i końcowy, więc wyświetlana jest tylko część elipsy. Myślę, że będzie to wymagać albo narysowania sześciennej krzywej Beziera, albo kwadratowej krzywej Beziera. Problem polega na tym, że nie mam pojęcia, jak obliczyć punkt początkowy, punkt końcowy lub punkty kontrolne za pomocą informacji, które otrzymałem.

Odpowiedz

9

Prawdopodobnie można osiągnąć to, co chcesz, poprzez utworzenie ścieżki klipu wokół rysunku elipsy.

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

Dokładny promień przycinania nie jest ważny. Musi być na tyle duży, aby tylko zaciskał elipsę na końcach, a nie przez pożądany łuk.

+0

Dzięki, działał jak czar (wciąż nowy w Objective-C, a także w rysowaniu grafiki). –

2

Będziesz musiał użyć addQuadCurveToPoint:controlPoint: zamiast bezierPathWithOvalInRect.

Definicja metoda jest jako: -

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

czyli CGPoint są argumenty (wejście) dla obu parametrów.

Musisz również ustawić punkt początkowy, używając moveToPoint:, zanim zadzwonisz pod numer addQuadCurveToPoint, który będzie działał jako bieżący punkt (ponieważ możesz zobaczyć, że nie ma punktu początkowego jako parametru w metodzie).

W twoim przypadku trzeba będzie

1> x, y jako punkt wyjścia

2> x + y + szerokość i wysokość w końcowym

nie trzeba tutaj lub kątów możesz zaimplementować swoją logikę, aby użyć kątów. Wysyłając obraz, aby wszystko było jasne.

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

+0

Krzywa kwadratowa Beziera nie będzie działać. Być może możesz obliczyć punkty kontrolne dla sześciennej krzywej Beziera tak, że elipsa zostanie narysowana z podanymi właściwościami.Bez matematyki potrzebnej do przetłumaczenia podanych informacji na krzywą Beziera, nie stanowi to odpowiedzi na pytanie. – thundersteele

+0

W rzeczywistości myślę, że jeśli chcesz narysować ścieżkę jawnie (tj. NOT with clipping) potrzebujesz równania parametrycznego dla elipse. Będziesz musiał wykonać kilka krótkich segmentów (kwadratowych lub sześciennych, a nawet liniowych), które ZBLIŻAJĄ się w elipse. Obcinanie jest lepsze. – samson

+1

To wielki Techotopia: http://www.techotopia.com/index.php/An_iPhone_Graphics_Drawing_Tutorial_using_Quartz_2D#Drawing_an_Ellipse_or_Circle – Aardvark

3

Ta kategoria pomoże.

#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

Świetna kategoria !!! Żeby było idealnie, pierwszy punkt dodania linii nie powinien zawierać punktu początkowego, który jest pierwszymEllipsePoint w powyższym kodzie. Zatem wyrażenie 'for' powinno być' for (CGFloat angle = startAngle + angleStep; angle

+0

@RungeZhai: to prawda, gotowe! – kanobius

+0

Wydaje się, że ellipsePointForAngle jest niepoprawny lub występują rozbieżności, które różnią się dla używanej przeze mnie metody. Wraz ze wzrostem kąta wokół owalu, wygląda nieco na przesunięcie w przód iw tył. Częściowo wynika to z braku szerokości i wysokości elipsy, co jest ważne i różni się od znalezienia punktu na okręgu pod kątem. – VagueExplanation

Powiązane problemy