Calculating Bezier points

Screen Shot 2013-03-24 at 4.08.38 PM

iOS supports three kind of Bezier elements: line segments, quadratic curves, and cubic curves.  Each of these participate in the UIBezierPath class to create complex shapes for UIKit and Quartz drawing routines.

Retrieving the component curves provides a powerful development tool. It enables you to transform paths by scaling, rotation , and translation, and provides a basis for applying drawing functions along the curve.

For example, you may want to place or draw items along the curve  to create fun text layouts or to animate gameplay. Knowing where things fall is key.

Screen Shot 2013-03-24 at 4.51.45 PM

Unfortunately, the CGPathElement structure doesn’t offer you much to work with. It provides an element type, which might be one of: move to point, add line to point, add curve to point, add quad curve to point, or close path.

A variable-sized array of CGPoints, depending on the number of parameters used to define that element. Close and move operations include no parameters. The curve-to-point operation uses three.

So how do you calculate the intermediate points between one point and the next? Well, with linear items, it’s easy. You calculate the vector from one point to the next and scale it to the percent of progress.

- (CGPoint) interpolateFrom: (CGPoint) p1 to: (CGPoint) p2 
    withPercent: (CGFloat) percent withSlope: (CGPoint *) slope
{
    CGFloat dx = p2.x - p1.x;
    CGFloat dy = p2.y - p1.y;

    if (slope)
        *slope = CGPointMake(dx, dy);

    CGFloat px = p1.x + dx * percent;
    CGFloat py = p1.y + dy * percent;

    return CGPointMake(px, py);
}

But given a curve, how do you interpolate? Fortunately, you can just apply the base curve math. Here’s are cubic (2 control points) and quadradic (1 control point) functions to calculate those values. You supply the percent of progress (from 0 to 1), the start value, the end value, and the one or two control values.

float CubicBezier(float t, float start, float c1, float c2, float end)
{
    CGFloat t_ = (1.0 - t);
    CGFloat tt_ = t_ * t_;
    CGFloat ttt_ = t_ * t_ * t_;
    CGFloat tt = t * t;
    CGFloat ttt = t * t * t;

    return start * ttt_
    + 3.0 *  c1 * tt_ * t
    + 3.0 *  c2 * t_ * tt
    + end * ttt;
}

float QuadBezier(float t, float start, float c1, float end)
{
    CGFloat t_ = (1.0 - t);
    CGFloat tt_ = t_ * t_;
    CGFloat tt = t * t;

    return start * tt_
    + 2.0 *  c1 * t_ * t
    + end * tt;
}

For example, lets say you have two points A and B, and a control point C1. You want to calculate the value 30% of the way between the two of them. Call the function twice, once for the x value, once for the y. Combine the two to produce a destination point.

P.x = QuadBezier(0.3, A.x, C1.x, B.x);
P.y = QuadBezier(0.3, A.y, C1.y, B.y);
return CGPointMake(P.x, P.y);

One Comment

  • How to calculate the control point C1 between A and B