2011-05-03 7 views
9

Tengo el siguiente código:¿Por qué la unión no se redondea cuando la línea dobla nuevamente sobre sí misma?

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

Esto genera el siguiente resultado:

Output of the code

¿Hay una buena razón por la que el borde inferior de la forma roja no se completa? ¿O es un error en Core Graphics cuando la línea se duplica exactamente en sí misma?

Respuesta

4

Definitivamente es un error. Si intenta agregar otra línea a la ruta, puede ver cómo Core Graphics no puede manejarla.

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

Es como si el enmascaramiento que crea las tapas redondeadas y se une se invierte cuando se duplicó.

+0

Por supuesto, los * extremos * de la línea son redondeados, eso es 'CGContextSetLineCap' y no es la pregunta aquí. La pregunta es por qué 'CGContextSetLineJoin' con' kCGLineJoinRound' no redondea la unión cuando la ruta gira 180 ° (pero lo hace cuando se convierte en algo así como 179.427 °). – Anomie

+0

Disculpa, acabo de ver el límite de la línea y pasé por alto la unión de la línea. Probablemente hayas encontrado un error. La documentación de kCGLineJoinRound establece claramente que las uniones deben redondearse, pero obviamente no lo son. –

+0

Actualizado mi respuesta. –

3

Mortenfast demostró que esto es un error. Pero publicaré esta respuesta para ofrecer mi solución.

Una solución consiste en detectar este caso y añadir un segmento de línea muy corta perpendicular a la línea existente, algo como esto:

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

Esto necesita una Ivar llamado prevPt, y opera en el camino en el Ivar currentPath.

Cuestiones relacionadas