Get position of path at time

2d, cashapelayer, core-animation, core-graphics, objective-c

Solution

You can definitely base your approach on the CADisplayLink and a tracking layer. However, if you don't mind doing a little bit of math on your own, the solution is not too complicated. Plus, you wont have to depend on setting up a display link and extra layers. In fact, you dont even have to depend on QuartzCore.

The following will work for any CGPathRef. In case of a UIBezierPath, fetch the CGPath property of the same:

- Use `CGPathApply` on the path you want to introspect along with a custom `CGPathApplierFunction` function.

- Your `CGPathApplierFunction` will be invoked for each component of that path. The CGPathElement (an argument to the applier) will tell you what kind of a path element it is along with the points that make that element (control points or endpoints).

- You will be given one, two, three and four points for `kCGPathElementMoveToPoint`, `kCGPathElementAddLineToPoint`, `kCGPathElementAddQuadCurveToPoint` and `kCGPathElementAddCurveToPoint` respectively.

- Store these points internally in a representation of your choosing. You only need to use the `CGPathApply` once per path and this step is extremely fast.

Now, onto the math:

- Based on the time you wish to find the position at, say `t`, get the element (more on this later) and its constituent points.

- If the element type is `kCGPathElementMoveToPoint`, its a linear interpolation `p0 + t * (p1 - p0)` (for x and y)

- If the element type is `kCGPathElementAddQuadCurveToPoint`, its quadratic `((1 - t) * (1 - t)) * p0 + 2 * (1 - t) * t * p1 + t * t * p2`

- If the element type is `kCGPathElementAddCurveToPoint`, its a cubic bezier `((1 - t) * (1 - t) * (1 - t)) * p0 + 3 * (1 - t) * (1 - t) * t * p1 + 3 * (1 - t) * t * t * p2 + t * t * t * p3`

Now the question remains, how do you figure out the path element at time `t`. You can assume each path element gets an equal time slice or you can calculate the distance of each element and account for the fractional time (the former approach works fine for me). Also, don't forget to add the times for all previous path elements (you dont have to find the interpolations for these).

As I said, this is just for completeness (and likely how Apple figures out this stuff out themselves) and only if you are willing to do the math.

Problem

is there a nice way to calculate the position of a path (CGPath or UIBezierPath) at a given time (from 0 to 1)? Using CAShapeLayer for example, one can create an animated stroke end. I want to know the position of that stroke end at arbitrary times. Thanks in advance, Adrian

Original source