2011-12-09 49 views
9

我試圖適應蘋果以編程方式繪製一線明星提供了一個示例,代碼如下:如何使用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); 
    } 

上面的代碼繪製一個完美的明星,但爲1翻轉顯示2.是黑色的,沒有邊界。我想要達到的目的是在同一條線上和給定的風格上畫出許多恆星。我知道我實際上在同一個位置上繪製了相同的路徑5次,並且我以某種方式垂直翻轉了上下文,但經過幾次測試後,我放棄了! (我缺乏必要的數學和幾何技能:P)...你能幫我嗎?

UPDATE:

好,感謝CocoaFu,這是我的重構和工作抽獎工具:

- (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

你是什麼意思倒掛?明星沒有「底」,我錯了嗎?也許你可以張貼一些截圖,你目前得到的和你的期望。 –

+0

星星的底部通常有一個頂點和一個2點。正常明星:http://www.allstarbaseballcamp.com/star_clipart.gif,顛倒(垂直翻轉)明星:http://sunandshield.files.wordpress.com/2010/03/eastern-star.jpg – daveoncode

+0

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

回答

28

這裏是代碼,將在一個水平線上畫3個星,這是並不漂亮,但它可能有所幫助:

-(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

非常感謝!無論如何,恆星仍然處於錯誤的位置......我如何垂直翻轉它們? (我感到一個白癡:P) – daveoncode

+0

我解決了使用:CGAffineTransform verticalFlip = CGAffineTransformMake(1,0,0,-1,0,w); CGContextConcatCTM(context,verticalFlip); ...有沒有更好的辦法? – daveoncode

+0

可能有,因爲通過這樣做,你在通話後繪製的任何東西都會顛倒。所以你應該在繪製星星之後恢復變形,以防你想繪製其他東西。 –

7

下面是實現一種算法是什麼buddhabrot暗示:

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

作品對我來說最基本的明星。測試2點(製作好鑽石!)達9星。

如果您想要一個帶點的星形,請將減法更改爲加法。

要繪製倍數,創建一個循環並多次調用此方法,每次都傳遞一個新中心。這應該排隊他們很好!

+0

五星級的「innerRadius/outerRadius」與「完美」的比例是什麼?(如另一個答案中繪製的那個)? – Colas

+0

我不知道我是否會將其他答案稱爲「完美」,但我相信比例是2/5(innerRadius/outerRadius) – gavdotnet

4

我更喜歡使用​​來實現drawRect,因爲它可以被動畫化。 這裏,將在5點星形的創建路徑的功能:

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 
} 

然後它可以用CAShapeLayer使用像這樣:

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