iphone ios drawing bezier

iphone - ¿Por qué UIBezierPath es más rápido que la ruta de Core Graphics?



ios drawing (1)

Tiene razón en que UIBezierPath es simplemente un contenedor objetivo-c para Core Graphics, y por lo tanto funcionará de forma comparable. La diferencia (y la razón de su delta de rendimiento) es su estado CGContext cuando dibujar su CGPath directamente es bastante diferente a la configuración de UIBezierPath . Si miras UIBezierPath , tiene configuraciones para:

  • lineWidth ,
  • lineJoinStyle ,
  • lineCapStyle ,
  • miterLimit y
  • flatness

Al examinar la llamada (desmontaje) a [path stroke] , observará que configura el contexto gráfico actual en función de esos valores previos antes de realizar la llamada CGContextStrokePath . Si haces lo mismo antes de dibujar tu CGPath, se realizará de la misma manera:

- (void)drawRect:(CGRect)rect { CGContextRef ctx = UIGraphicsGetCurrentContext(); // Create the two paths, cgpath and uipath. CGMutablePathRef cgpath = CGPathCreateMutable(); CGPathMoveToPoint(cgpath, NULL, 0, 100); UIBezierPath *uipath = [[UIBezierPath alloc] init]; [uipath moveToPoint:CGPointMake(0, 200)]; // Add 200 curve segments to each path. int iterations = 80000; CGFloat cgBaseline = 100; CGFloat uiBaseline = 200; CGFloat xincrement = self.bounds.size.width / iterations; for (CGFloat x1 = 0, x2 = xincrement; x2 < self.bounds.size.width; x1 = x2, x2 += xincrement) { CGPathAddCurveToPoint(cgpath, NULL, x1, cgBaseline-50, x2, cgBaseline+50, x2, cgBaseline); [uipath addCurveToPoint:CGPointMake(x2, uiBaseline) controlPoint1:CGPointMake(x1, uiBaseline-50) controlPoint2:CGPointMake(x2, uiBaseline+50)]; } [[UIColor blackColor] setStroke]; CGContextAddPath(ctx, cgpath); // Stroke each path CGContextSaveGState(ctx); { // configure context the same as uipath CGContextSetLineWidth(ctx, uipath.lineWidth); CGContextSetLineJoin(ctx, uipath.lineJoinStyle); CGContextSetLineCap(ctx, uipath.lineCapStyle); CGContextSetMiterLimit(ctx, uipath.miterLimit); CGContextSetFlatness(ctx, uipath.flatness); [self strokeContext:ctx]; CGContextRestoreGState(ctx); } [self strokeUIBezierPath:uipath]; [uipath release]; CGPathRelease(cgpath); } - (void)strokeContext:(CGContextRef)context { CGContextStrokePath(context); } - (void)strokeUIBezierPath:(UIBezierPath*)path { [path stroke]; }

Instantánea de los instrumentos:

Estaba jugando con dibujar caminos, y noté que en al menos algunos casos, UIBezierPath supera lo que pensé que sería un equivalente de Core Graphics. El método -drawRect: continuación crea dos rutas: una UIBezierPath y una CGPath. Los caminos son idénticos, excepto por su ubicación, pero acariciar el CGPath toma aproximadamente el doble de tiempo que acariciar el UIBezierPath.

- (void)drawRect:(CGRect)rect { CGContextRef ctx = UIGraphicsGetCurrentContext(); // Create the two paths, cgpath and uipath. CGMutablePathRef cgpath = CGPathCreateMutable(); CGPathMoveToPoint(cgpath, NULL, 0, 100); UIBezierPath *uipath = [[UIBezierPath alloc] init]; [uipath moveToPoint:CGPointMake(0, 200)]; // Add 200 curve segments to each path. int iterations = 200; CGFloat cgBaseline = 100; CGFloat uiBaseline = 200; CGFloat xincrement = self.bounds.size.width / iterations; for (CGFloat x1 = 0, x2 = xincrement; x2 < self.bounds.size.width; x1 = x2, x2 += xincrement) { CGPathAddCurveToPoint(cgpath, NULL, x1, cgBaseline-50, x2, cgBaseline+50, x2, cgBaseline); [uipath addCurveToPoint:CGPointMake(x2, uiBaseline) controlPoint1:CGPointMake(x1, uiBaseline-50) controlPoint2:CGPointMake(x2, uiBaseline+50)]; } [[UIColor blackColor] setStroke]; CGContextAddPath(ctx, cgpath); // Stroke each path. [self strokeContext:ctx]; [self strokeUIBezierPath:uipath]; [uipath release]; CGPathRelease(cgpath); } - (void)strokeContext:(CGContextRef)context { CGContextStrokePath(context); } - (void)strokeUIBezierPath:(UIBezierPath*)path { [path stroke]; }

Ambas rutas utilizan CGContextStrokePath (), así que creé métodos separados para recorrer cada ruta, de modo que pueda ver el tiempo utilizado por cada ruta en Instrumentos. A continuación se muestran los resultados típicos (árbol de llamadas invertidas); puedes ver que -strokeContext: toma 9.5 segundos, mientras que -strokeUIBezierPath: toma solo 5 segundos .:

Running (Self) Symbol Name 14638.0ms 88.2% CGContextStrokePath 9587.0ms 57.8% -[QuartzTestView strokeContext:] 5051.0ms 30.4% -[UIBezierPath stroke] 5051.0ms 30.4% -[QuartzTestView strokeUIBezierPath:]

Parece que UIBezierPath está de alguna manera optimizando el camino que crea, o estoy creando el CGPath de una manera ingenua. ¿Qué puedo hacer para acelerar mi dibujo de CGPath?