Over the last few posts I wrote about things I did to improve font quality, such as antialiasing and combining distance fields to merge outlines and halos. But I want to “pop up the stack” a bit and talk about one of the bigger goals for this project. I want to render text in styles that I’ve seen in maps, both online and offline, both fantasy and real. In particular, I want to apply spacing, rotation, and curvature to the labels.
These are common in cartography, not only in fantasy maps like Tolkein’s but also in real-world maps. Eduard Imhof’s classic 1975 paper, Positioning Names on Maps[1] has a ton of great advice on how to position labels, and not only recommends curving text, but also sketches out examples:
I’ve had this paper sitting on my computer desktop since 2011. And I’m sure I was interested in this topic long before then. I will be re-reading it again before writing a label placement algorithm. Both Apple Maps and Google Maps use curved text, as shown in these examples:
Fantasy maps used curved text too. Tolkein’s Lord of the Rings maps used curved text for areas and rivers. Scott Turner’s inspirational blog includes a post Labeling the Coast part two[2] in which he shows how he analyzed the coastline to find a suitable curved arc, and also that he liked curved arcs better than more complex paths. There are also posts on Cartographers Guild[3] about when and how to use curved labels.
So I want to implement curved labels.
To figure out how to make text flow along a curve, I first sketched it out on paper, then made a standalone interactive widget. There are three cases to handle:
- Positive curvature: the text should be positioned along the baseline.
- Zero curvature: the text is not curved.
- Negative curvature: the text should be positioned along the ascender line.
If I always curve at the baseline, the tops of the characters are too close together. That’s why I have to curve at the ascender line instead of the baseline when the curvature is negative:
After calculating the geometry, there are two ways I know of to render the curved text.
- “Curving” or “Wrapping”: Position and rotate each letter along a curved path, then render them onto the intermediate combined distance field.
- “Shaping” or “Warping”: Draw the letters first onto the intermediate combined distance field, then distort the entire label into a curved shape.
One advantage of warping over wrapping is that it allows for many more effects, such as these:
However, whenever stretching the label non-uniformly, the distance field gets distorted. In this example the white halo on the left side (The) is much larger vertically than horizontally. I can find a way to fix this but I decided not to pursue it, since I was primarily interested in curved text and not arbitary warpings:
Google’s guide[4] says wrapping generally works better than warping, but I ended up trying warping first, and decided I liked it well enough. However, in the last post I had said next time I might choose to not use an intermediate combined distance field. I think without that step, it would be easier to use wrapping than warping.
Using distance fields, I can apply the outline, halo, and antialiasing after the curving step. I’m very happy with the way the curved labels turned out.