2011-05-03 52 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