Wednesday, June 5, 2013

UIBezierPath addQuadCurveToPoint controlPoint example in Objective C (iOS).

UIBezierPath addQuadCurveToPoint controlPoint

Appends a quadratic Bézier curve to the receiver’s path.

- (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint

Parameters of [UIBezierPath addQuadCurveToPoint controlPoint]
The end point of the curve.
The control point of the curve.

Discussion of [UIBezierPath addQuadCurveToPoint controlPoint]
This method appends a quadratic Bézier curve from the current point to the end point specified by the endPoint parameter. The relationships between the current point, control point, and end point are what defines the actual curve. Figure 3 shows some examples of quadratic curves and the approximate curve shape based on some sample points. The exact curvature of the segment involves a complex mathematical relationship between the points and is well documented online.

Figure 3 Quadratic curve examples
UIBezierPath addQuadCurveToPoint

You must set the path’s current point (using the moveToPoint: method or through the previous creation of a line or curve segment) before you call this method. If the path is empty, this method does nothing. After adding the curve segment, this method updates the current point to the value in point.
UIBezierPath addQuadCurveToPoint controlPoint example.
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0, 10)];
[path addQuadCurveToPoint:CGPointMake(200, 10) controlPoint:CGPointMake(100, 5)];
[path addLineToPoint:CGPointMake(200, 0)];
[path addLineToPoint:CGPointMake(0, 0)];
[path closePath];

CGContextAddPath(context, path.CGPath);
[[UIColor redColor] set];

Example of [UIBezierPath addQuadCurveToPoint controlPoint].
void MyCGPathApplierFunc (void *info, const CGPathElement *element) {

UIBezierPath *drawingPath = (UIBezierPath *)info;
CGPoint *points = element->points;
CGPathElementType type = element->type;

switch(type) {
    case kCGPathElementMoveToPoint: // contains 1 point
        [drawingPath moveToPoint:[[NSValue valueWithCGPoint:points[0]] CGPointValue]];

    case kCGPathElementAddLineToPoint: // contains 1 point
        [drawingPath addLineToPoint:[[NSValue valueWithCGPoint:points[0]] CGPointValue]];
    case kCGPathElementAddQuadCurveToPoint: // contains 1 point
        [drawingPath addQuadCurveToPoint:[[NSValue valueWithCGPoint:points[0]] CGPointValue]];

   case kCGPathElementAddCurveToPoint: // contains 1 point
        [drawingPath addCurveToPoint:[[NSValue valueWithCGPoint:points[0]] CGPointValue]];

    case kCGPathElementCloseSubpath: // contains no point

UIBezierPath addQuadCurveToPoint controlPoint example.
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path setLineWidth:3.0];
    [path setLineCapStyle:kCGLineCapRound];
    [path setLineJoinStyle:kCGLineJoinRound];

    // actualPoints are my points array stored as NSValue

    NSValue *value = [actualPoints objectAtIndex:0];
    CGPoint p1 = [value CGPointValue];
    [path moveToPoint:p1];

    for (int k=1; k<[actualPoints count];k++) {

        NSValue *value = [actualPoints objectAtIndex:k];
        CGPoint p2 = [value CGPointValue];

        CGPoint centerPoint = CGPointMake((p1.x+p2.x)/2, (p1.y+p2.y)/2);

        // See if your curve is decreasing or increasing
        // You can optimize it further by finding point on normal of line passing through midpoint

        if (p1.y<p2.y) {
             centerPoint = CGPointMake(centerPoint.x, centerPoint.y+(abs(p2.y-centerPoint.y)));
        }else if(p1.y>p2.y){
             centerPoint = CGPointMake(centerPoint.x, centerPoint.y-(abs(p2.y-centerPoint.y)));

        [path addQuadCurveToPoint:p2 controlPoint:centerPoint];
        p1 = p2;

    [path stroke];

End of UIBezierPath addQuadCurveToPoint controlPoint example article.