2011-12-09 39 views
9

Tôi đang cố gắng để thích nghi với một ví dụ cung cấp bởi Apple để lập trình vẽ ngôi sao trong dòng, mã này là như sau:Làm thế nào để vẽ sao bằng Quartz Core?

CGContextRef context = UIGraphicsGetCurrentContext(); 
CGContextSetLineWidth(context, aSize); 

    for (NSUInteger i=0; i<stars; i++) 
    { 

     CGContextSetFillColorWithColor(context, aColor); 
     CGContextSetStrokeColorWithColor(context, aColor); 

     float w = item.size.width; 
     double r = w/2; 
     double theta = 2 * M_PI * (2.0/5.0); // 144 degrees 

     CGContextMoveToPoint(context, 0, r); 

     for (NSUInteger k=1; k<5; k++) 
     { 
      float x = r * sin(k * theta); 
      float y = r * cos(k * theta); 
      CGContextAddLineToPoint(context, x, y); 
     } 

     CGContextClosePath(context); 
     CGContextFillPath(context); 
    } 

Đoạn mã trên vẽ một ngôi sao hoàn hảo, nhưng là 1. hiển thị đã lộn ngược 2. là màu đen và không có viền. Những gì tôi muốn đạt được là vẽ nhiều ngôi sao trên cùng một dòng và với phong cách nhất định. Tôi hiểu rằng tôi thực sự vẽ cùng một con đường 5 lần trong cùng một vị trí và rằng tôi đã bằng cách nào đó để lật ngữ cảnh theo chiều dọc, nhưng sau một vài bài kiểm tra tôi đã từ bỏ! (Tôi thiếu các kỹ năng toán học và hình học cần thiết: P) ... bạn có thể giúp tôi được không?

UPDATE:

Ok, nhờ CocoaFu, đây là tiện ích rút thăm refactored và làm việc của tôi:

- (void)drawStars:(NSUInteger)count inContext:(CGContextRef)context; 
{ 
    // constants 
    const float w = self.itemSize.width; 
    const float r = w/2; 
    const double theta = 2 * M_PI * (2.0/5.0); 
    const float flip = -1.0f; // flip vertically (default star representation) 

    // drawing center for the star 
    float xCenter = r; 

    for (NSUInteger i=0; i<count; i++) 
    { 
     // get star style based on the index 
     CGContextSetFillColorWithColor(context, [self fillColorForItemAtIndex:i]); 
     CGContextSetStrokeColorWithColor(context, [self strokeColorForItemAtIndex:i]); 

     // update position 
     CGContextMoveToPoint(context, xCenter, r * flip + r); 

     // draw the necessary star lines 
     for (NSUInteger k=1; k<5; k++) 
     { 
      float x = r * sin(k * theta); 
      float y = r * cos(k * theta); 
      CGContextAddLineToPoint(context, x + xCenter, y * flip + r); 
     } 

     // update horizontal center for the next star 
     xCenter += w + self.itemMargin; 

     // draw current star 
     CGContextClosePath(context); 
     CGContextFillPath(context); 
     CGContextStrokePath(context); 
    } 
} 
+0

Ý anh là gì lộn ngược? Một ngôi sao không có 'đáy' như vậy, tôi có sai không? Có lẽ bạn có thể đăng một vài ảnh chụp màn hình, về những gì bạn đang nhận được và những gì bạn đang mong đợi. –

+0

Một ngôi sao thường có một điểm ở đầu một 2 ở phía dưới. Ngôi sao bình thường: http://www.allstarbaseballcamp.com/star_clipart.gif, sao lộn ngược (dọc) sao: http://sunandshield.files.wordpress.com/2010/03/eastern-star.jpg – daveoncode

+0

Xem https: //calayer.com/core-animation/2016/05/22/cashapelayer-in-depth.html#path – iwasrobbed

Trả lời

28

Đây là mã mà sẽ vẽ 3 ngôi sao trong một đường ngang, đó là không đẹp nhưng nó có thể giúp:

-(void)drawRect:(CGRect)rect 
{ 
    int aSize = 100.0; 
    const CGFloat color[4] = { 0.0, 0.0, 1.0, 1.0 }; // Blue 
    CGColorRef aColor = CGColorCreate(CGColorSpaceCreateDeviceRGB(), color); 
    CGContextRef context = UIGraphicsGetCurrentContext(); 
    CGContextSetLineWidth(context, aSize); 
    CGFloat xCenter = 100.0; 
    CGFloat yCenter = 100.0; 

    float w = 100.0; 
    double r = w/2.0; 
    float flip = -1.0; 

    for (NSUInteger i=0; i<3; i++) 
    { 
     CGContextSetFillColorWithColor(context, aColor); 
     CGContextSetStrokeColorWithColor(context, aColor); 

     double theta = 2.0 * M_PI * (2.0/5.0); // 144 degrees 

     CGContextMoveToPoint(context, xCenter, r*flip+yCenter); 

     for (NSUInteger k=1; k<5; k++) 
     { 
      float x = r * sin(k * theta); 
      float y = r * cos(k * theta); 
      CGContextAddLineToPoint(context, x+xCenter, y*flip+yCenter); 
     } 
     xCenter += 150.0; 
    } 
    CGContextClosePath(context); 
    CGContextFillPath(context); 
} 

enter image description here

+0

cảm ơn rất nhiều! Dù sao các ngôi sao vẫn còn ở vị trí sai ... làm thế nào tôi có thể lật chúng theo chiều dọc? (Tôi cảm thấy một thằng ngốc: P) – daveoncode

+0

Tôi đã giải quyết bằng cách sử dụng: CGAffineTransform verticalFlip = CGAffineTransformMake (1, 0, 0, -1, 0, w); CGContextConcatCTM (context, verticalFlip); ...Có cách nào tốt hơn? – daveoncode

+0

Có thể có, bởi vì bằng cách làm tất cả mọi thứ bạn vẽ sau khi cuộc gọi sẽ được lộn ngược. Vì vậy, bạn nên hoàn nguyên biến đổi sau khi vẽ các ngôi sao, trong trường hợp bạn muốn vẽ một cái gì đó khác. –

7

Dưới đây là một thuật toán để thực hiện những gì buddhabrot ngụ ý:

- (void)drawStarInContext:(CGContextRef)context withNumberOfPoints:(NSInteger)points center:(CGPoint)center innerRadius:(CGFloat)innerRadius outerRadius:(CGFloat)outerRadius fillColor:(UIColor *)fill strokeColor:(UIColor *)stroke strokeWidth:(CGFloat)strokeWidth { 
    CGFloat arcPerPoint = 2.0f * M_PI/points; 
    CGFloat theta = M_PI/2.0f; 

    // Move to starting point (tip at 90 degrees on outside of star) 
    CGPoint pt = CGPointMake(center.x - (outerRadius * cosf(theta)), center.y - (outerRadius * sinf(theta))); 
    CGContextMoveToPoint(context, pt.x, pt.y); 

    for (int i = 0; i < points; i = i + 1) { 
     // Calculate next inner point (moving clockwise), accounting for crossing of 0 degrees 
     theta = theta - (arcPerPoint/2.0f); 
     if (theta < 0.0f) { 
      theta = theta + (2 * M_PI); 
     } 
     pt = CGPointMake(center.x - (innerRadius * cosf(theta)), center.y - (innerRadius * sinf(theta))); 
     CGContextAddLineToPoint(context, pt.x, pt.y); 

     // Calculate next outer point (moving clockwise), accounting for crossing of 0 degrees 
     theta = theta - (arcPerPoint/2.0f); 
     if (theta < 0.0f) { 
      theta = theta + (2 * M_PI); 
     } 
     pt = CGPointMake(center.x - (outerRadius * cosf(theta)), center.y - (outerRadius * sinf(theta))); 
     CGContextAddLineToPoint(context, pt.x, pt.y); 
    } 
    CGContextClosePath(context); 
    CGContextSetLineWidth(context, strokeWidth); 
    [fill setFill]; 
    [stroke setStroke]; 
    CGContextDrawPath(context, kCGPathFillStroke); 
} 

trình đối với tôi cho hầu hết các ngôi sao cơ bản. Được thử nghiệm từ 2 điểm (tạo ra một viên kim cương tốt!) Lên đến 9 sao.

Nếu bạn muốn một ngôi sao có điểm xuống, hãy thay đổi phép trừ để thêm vào.

Để vẽ bội số, tạo vòng lặp và gọi phương thức này nhiều lần, mỗi lần đi qua một trung tâm mới. Điều đó nên xếp chúng lên một cách độc đáo!

+0

Tỷ lệ 'innerRadius/outerRadius' đối với sao 5 sao là" hoàn hảo "(giống như tỷ lệ được vẽ trong câu trả lời khác)? – Colas

+0

Tôi không biết liệu tôi có thể gọi ngôi sao trong câu trả lời khác "hoàn hảo" hay không, nhưng tôi tin tỷ lệ này là 2/5 (innerRadius/outerRadius) – gavdotnet

4

Tôi thích sử dụng CAShaperLayer để triển khai drawRect, vì sau đó có thể được làm động. Dưới đây là một chức năng mà sẽ tạo ra một đường dẫn trong hình dạng của một ngôi sao 5 điểm:

func createStarPath(size: CGSize) -> CGPath { 
    let numberOfPoints: CGFloat = 5 

    let starRatio: CGFloat = 0.5 

    let steps: CGFloat = numberOfPoints * 2 

    let outerRadius: CGFloat = min(size.height, size.width)/2 
    let innerRadius: CGFloat = outerRadius * starRatio 

    let stepAngle = CGFloat(2) * CGFloat(M_PI)/CGFloat(steps) 
    let center = CGPoint(x: size.width/2, y: size.height/2) 

    let path = CGPathCreateMutable() 

    for i in 0..<Int(steps) { 
     let radius = i % 2 == 0 ? outerRadius : innerRadius 

     let angle = CGFloat(i) * stepAngle - CGFloat(M_PI_2) 

     let x = radius * cos(angle) + center.x 
     let y = radius * sin(angle) + center.y 

     if i == 0 { 
      CGPathMoveToPoint(path, nil, x, y) 
     } 
     else { 
      CGPathAddLineToPoint(path, nil, x, y) 
     } 
    } 

    CGPathCloseSubpath(path) 
    return path 
} 

Sau đó nó có thể được sử dụng với một CAShapeLayer như vậy:

let layer = CAShapeLayer() 
layer.path = createStarPath(CGSize(width: 100, height: 100)) 
layer.lineWidth = 1 
layer.strokeColor = UIColor.blackColor().CGColor 
layer.fillColor = UIColor.yellowColor().CGColor 
layer.fillRule = kCAFillRuleNonZero 
Các vấn đề liên quan