2011-05-03 51 views
9

我有以下代碼:爲什麼連線在自身翻倍時不會變圓?

- (void)drawRect:(CGRect)rect { 
    CGContextRef c = UIGraphicsGetCurrentContext(); 

    CGContextSetFillColorWithColor(c, [UIColor blackColor].CGColor); 
    CGContextFillRect(c, rect); 

    CGContextSetLineJoin(c, kCGLineJoinRound); 
    CGContextSetLineCap(c, kCGLineCapRound); 
    CGContextSetLineWidth(c, 50.0); 

    CGContextSetStrokeColorWithColor(c, [UIColor redColor].CGColor); 
    CGContextBeginPath(c); 
    CGContextMoveToPoint(c, 60, 60); 
    CGContextAddLineToPoint(c, 60, 250); 
    CGContextAddLineToPoint(c, 60, 249); 
    CGContextStrokePath(c); 

    CGContextSetStrokeColorWithColor(c, [UIColor blueColor].CGColor); 
    CGContextBeginPath(c); 
    CGContextMoveToPoint(c, 160, 60); 
    CGContextAddLineToPoint(c, 160, 250); 
    CGContextAddLineToPoint(c, 160.01, 249); 
    CGContextStrokePath(c); 
} 

這將生成以下的輸出:

Output of the code

是否有一個很好的理由,紅色形狀的底部邊緣是不是圓的?或者它是否是Core Graphics中的一個錯誤?

回答

4

這絕對是一個錯誤。如果您嘗試在路徑中添加另一行,您可以看到Core Graphics無法處理它。

CGContextMoveToPoint(c, 60.0, 60.0); 
CGContextAddLineToPoint(c, 60.0, 250.0); 
CGContextAddLineToPoint(c, 60.0, 249.0); 
CGContextAddLineToPoint(c, 60.0, 250.0); 

enter image description here

就好像是創建圓帽,加入屏蔽時,它的一倍得到反轉。

+0

當然這行的* ends *是四捨五入的,即'CGContextSetLineCap',這裏不是問題。問題是爲什麼'CGContextSetLineJoin'和'kCGLineJoinRound'在路徑變成180°時沒有繞過連接(但當它變成類似179.427°的東西時)。 – Anomie 2011-06-23 14:31:17

+0

對不起,我剛看到線帽,忽略了線條連接。你很可能找到了一個錯誤。 kCGLineJoinRound的文檔清楚地表明連接應該四捨五入,但顯然不是。 – 2011-06-23 20:07:15

+0

更新了我的答案。 – 2011-06-24 05:48:48

3

mortenfast證明這是一個錯誤。但我會發布這個答案來提供我的解決方法。

一種解決方法是檢測這種情況下垂直添加一個很短的線段到現有的行,像這樣:

- (void)addPtToPath:(CGPoint)newPt { 
    // CoreGraphics seems to have a bug if a path doubles back on itself. 
    // Detect that and apply a workaround. 
    CGPoint curPt = CGPathGetCurrentPoint(self.currentPath); 
    if (!CGPointEqualToPoint(newPt, curPt)) { 
     CGFloat slope1 = (curPt.y - prevPt.y)/(curPt.x - prevPt.x); 
     CGFloat slope2 = (curPt.y - newPt.y)/(curPt.x - newPt.x); 
     CGFloat diff; 
     BOOL between; 
     if (isinf(slope1) && isinf(slope2)) { 
      // Special-case vertical lines 
      diff = 0; 
      between = ((prevPt.y < curPt.y) != (curPt.y < newPt.y)); 
     } else { 
      diff = slope1 - slope2; 
      between = ((prevPt.x < curPt.x) != (curPt.x < newPt.x)); 
     } 
     if (between && diff > -0.1 && diff < 0.1) { 
      //NSLog(@"Hack alert! (%g,%g) (%g,%g) (%g,%g) => %g %g => %g", prevPt.x, prevPt.y, curPt.x, curPt.y, newPt.x, newPt.y, slope1, slope2, diff); 
      if (isinf(slope1)) { 
       curPt.x += 0.1; 
      } else if (slope1 == 0) { 
       curPt.y += 0.1; 
      } else if (slope1 < -1 || slope1 > 1) { 
       curPt.x += 0.1; curPt.y -= 0.1/slope1; 
      } else { 
       curPt.x -= 0.1 * slope1; curPt.y += 0.1; 
      } 
      CGPathAddLineToPoint(self.currentPath, NULL, curPt.x, curPt.y); 
     } 
     prevPt = curPt; 
    } 
    CGPathAddLineToPoint(self.currentPath, NULL, newPt.x, newPt.y); 
} 

這需要一個名爲prevPt一個實例變量和路徑上的伊娃工作currentPath