Sunday, September 17, 2017

Labeling the Coast (Part One)

In the previous two postings I talked about labeling the ocean area of the map.  I have more to say about that, but for now I'm now going to turn my attention to labeling a coastline.  This is inspired by labels like these:
Here the mapmaker names a stretch of coastline with a label that roughly follows the coastline's shape.  Again, I'm not going to concern myself right now about how to come up with good names, but rather how to place them on the map.

Looking at the examples above, the basic idea seems pretty straightforward:  Select the section of coastline to label and then place the label in the water off the coastline along a very smoothed/simplified version of the coastline.

When I select the coastline to label, I'm going to look for a fairly flat section, like the "Dong Leng Tianh" example above.  The reason for this is (spoiler alert) that I also intend to label bays, as in these examples:
How do I tell when a bit of coastline is (relatively) straight?  When I talked about creating river labels, I introduced the notion of sinuosity.  Sinuosity is the ratio of the distance along a path to the distance between the end points of the path.  The higher this ratio, the more curved the path.  A straight line has a sinuosity of 1, because the length of the path is the same as the distance between the end points. A bay, in contrast is more like a semi-circle. What's the sinuosity of a semi-circle?
The distance between the end points of a semi-circle is the diameter D of the circle.  The distance along the semi-circle is half the circumference of the circle, (Pi*D)/2.  So the sinuosity of a semi-circle is Pi/2, or about 1.5.  Therefore a coastline with a sinuosity close to 1.5 is shaped something like a bay (semi-circle), while a sinuosity close to 1 is more like a straight stretch.  So I want to treat coastline labels the same as I do river labels, placing them on the straightest sections of the path (coastline).  In fact, I may be able to treat coastline labels exactly as I do river labels, just substituting the coastline for the river.

One of the example maps I was using for ocean labeling has a fairly straight coastline, so I'll use that as my test map during development:
And after some initial bug fixes and so on, here's a coastline label:
Here I've just arbitrarily placed the label at the middle of the coastline.  The way it has shifted suggests to me that the algorithm is incorrectly trying to place the upper-right hand corner of the label (where the purple dot is) at the center of the path rather than the center of the label.  The same problem is probably active in the river labels as well, although it's less obvious at that scale.

After a lot of debugging -- sometimes when I look at my old code I wonder if I was drunk when I wrote it -- I have something closer to right:
So far I've just been placing the coast label at the middle of the coastline.  That will get a little repetitive, so I can try placing the label randomly along the coastline:
This almost works on this map, but you can see the problem -- I've randomly selected a spot on the coast where the coast is not flat.  (Actually, that's a good location for a bay label!)  What I need to do is pick a random spot on the coastline where the sinuosity is low.  Here's an example where I've picked a spot with lower sinuosity:
Again, this almost works, but even on this path with much lower sinuosity the letters in the name end up clashing with each other.  (It looks pretty cool in this case, but that's just luck.)  To be honest, this is partly SVG's responsibility: It just doesn't do a very good job laying out text along a path.  But even when the letters don't clash, I find don't really like the look of text on an arbitrary path:
So I think I need to re-assess how I'm laying out and displaying path labels.  I don't think I need to change everything, but something that allows me to present decent labels along curvy paths would be great.  More on that in the next installment.

No comments:

Post a Comment