Text along a curve

I would like to draw text along a complex bezier curve. I've seen several examples on the web using CGPathApply

to do this. But those examples seem to be wrong. CGPathApply does not supply you with a series of points along

the curve. I just get back the points, and control points, I just used to specify the Bezier curve. I want actual

pixel coordinates of points along the curve. Is there some way to do this? Do I have to write my own

function to reproduce the Bezier curve points given the end points and control points? Has Apple documented

exactly the algorithm they use for doing this? Or is there some CG function I have overlooked that

does the evaluation for me? Or is there a CG function that takes a string and a path as arguments and

does the job for me?


Thanks.

Accepted Reply

Here is how to compute directly what you need.


Has Apple documented exactly the algorithm they use for doing this?

It is not Apple, it is Mr Bezier, an automotive engineer in the 80's.


There is a simple parametric form of a Bezier curve with n control points (Pi).

Detailed here:

h ttps://en.wikipedia.org/wiki/Bézier_curve


if t is a parameter between 0 and 1 (from start to end),

The formula can be expressed explicitly as follows (cannot print the forumla with nice typo on the forum, so I did my best to edit):


B(t) = Sigma [ C(n,i) (1-t)^(n-i) * (t ^ i) ] Pi

(0...n)


where C(n,i) are the binomial coefficients and Pi the control points ((x,y) coordinates).

For example, for n = 5:


B(t) = (1-t)^5 P0 + 5 t (1-t)^4 P1 + 10 t^2 (1-t)^3 P2 + 10 t^3 (1-t)^2 P3 + 5 t^4 (1-t) P4 + t^5 P5 0 ≤ t ≤1


With this formula, you can compute the exact coordinates of any point on the curve and find also the orientation of the tangent (so that letter "sits" on the curve by tilting with that tangent angle).

If P is (x,y), coordinates of the tangent vector at t are given by derivative (I split in 3 lines to make it more readable):

- C(n,0) n (1-t)^(n-i-1) P0

+

Sigma C(n,i) [ - (n-i) (1-t)^(n- i -1) * (t ^ i) + (1-t)^(n-i) * i (t ^ (i-1) ) ] Pi

(1…n-1)

+

C(n,n) t^(n-1) Pn


For t = 0

-C(n,0) n P0 + C(n,1) P1 = n (P1- P0): the direction is from P0 to P1 as well known.


Note: How many control points have you for your Bezier Path ?

Replies

You have visibly searched a lot, so I fear I will not bring any new information.


However, this post seems interesting

https://stackoverflow.com/questions/26857850/get-points-from-a-uibezierpath/26872803


Hope it will at least hint in a good direction.


Good luck.

There is sample code from Apple called textLayoutDemo that shows how to layout text in a circle. I'm not sure if this will help but it might be worth exploring. It dates back to about 2007 (I think).

A circle can be handled by direct computation. But it is not a Bezier curve.

Have you a link to the Apple's reference ?

Here is how to compute directly what you need.


Has Apple documented exactly the algorithm they use for doing this?

It is not Apple, it is Mr Bezier, an automotive engineer in the 80's.


There is a simple parametric form of a Bezier curve with n control points (Pi).

Detailed here:

h ttps://en.wikipedia.org/wiki/Bézier_curve


if t is a parameter between 0 and 1 (from start to end),

The formula can be expressed explicitly as follows (cannot print the forumla with nice typo on the forum, so I did my best to edit):


B(t) = Sigma [ C(n,i) (1-t)^(n-i) * (t ^ i) ] Pi

(0...n)


where C(n,i) are the binomial coefficients and Pi the control points ((x,y) coordinates).

For example, for n = 5:


B(t) = (1-t)^5 P0 + 5 t (1-t)^4 P1 + 10 t^2 (1-t)^3 P2 + 10 t^3 (1-t)^2 P3 + 5 t^4 (1-t) P4 + t^5 P5 0 ≤ t ≤1


With this formula, you can compute the exact coordinates of any point on the curve and find also the orientation of the tangent (so that letter "sits" on the curve by tilting with that tangent angle).

If P is (x,y), coordinates of the tangent vector at t are given by derivative (I split in 3 lines to make it more readable):

- C(n,0) n (1-t)^(n-i-1) P0

+

Sigma C(n,i) [ - (n-i) (1-t)^(n- i -1) * (t ^ i) + (1-t)^(n-i) * i (t ^ (i-1) ) ] Pi

(1…n-1)

+

C(n,n) t^(n-1) Pn


For t = 0

-C(n,0) n P0 + C(n,1) P1 = n (P1- P0): the direction is from P0 to P1 as well known.


Note: How many control points have you for your Bezier Path ?

As I said, it may be a starting point. A simple search in sample code:


https://developer.apple.com/library/archive/samplecode/TextLayoutDemo/Introduction/Intro.html#//apple_ref/doc/uid/DTS10004341

Did you try the proposed solution posted May 23, 2020 7:10 AM ?


Does it work as expected ?

The May 23 answer is baically the correct answer and the wikipedia reference is what I used to develop my code.

Knowing x and y isn't exactly what one needs of course and you don't know what x,y you are looking for either.

Instead one wishes to place each glyph a certain distance from the previous glyph, depending of glyph

bounding boxes. So what one really needs is the distance along the bezier curve. To address this I used

the bezier formula to sample a number of points between each segment of the bezier and then approximate

the curve with straight lines whose lengths I use to compute accumulated distance along the the curve.

I then find the two points on the bezier that bound the required distance and interpolate to achive

the final x,y. This is an approximation but is plenty good enough if the curve is sampled well enough.