Saturday, October 28, 2017

Labeling Islands (Part Two)

In the previous post, I looked at labeling island groups.  Island groups are relatively easy to identify because I make them intentionally during world creation.  However, Dragons Abound often creates islands unintentionally as a result of other terrain generation efforts.  For example, if Dragons Abound uses a noise function to create a base terrain, that often results in some islands.  I showed this example in the previous posting:
The two islands above the "Lost Coast" label are examples of incidental islands.

To label these islands, I first need to identify them.  This isn't too hard; Dragons Abound already identifies coastlines, so the islands can be identified by looking for coastlines where the start and the end are the same point.  Here's an example of that algorithm applied to a map:
The green outlines indicate islands.  There are a couple of things to note.  First, this has identified "Zhan Cay" as an island.  It is an island, but it was created by the algorithm that adds peninsula island chains and so already has a label.  Secondly, it has not identified the island in the lower right that is partly off-screen.

To address the first problem, I'll keep track of islands that are in island groups.  I may still want to label islands that are in island groups (especially large ones) but at least this way I'll know when an island is in a group.

The second problem arises because Dragons Abound doesn't close paths that vanish off-screen.  If it did, the coast for every land mass would be closed and detected as an island -- for example the middle land mass in the image above would be a big island.  And there's nothing to say that even small islands like the one in the above image are really islands; it could be just the tip of a large land mass.  Still, land masses like the small one in the lower right at least seem like islands and I probably should detect them as such. A reasonable compromise is to accept a land as an island if it is both (1) fairly small, and (2) the off-screen gap is not too big.

With these rules in place, only the upper island gets a name:
Here's a map where this doesn't work so well;
"Pir Lir Isle" is fine, but "Ozod Island" doesn't appear to be identifying any island.  It's just floating out in the middle of the water.  How did that happen?  Let's highlight the island outlines to see what it thinks it is labeling:
Aha!  The algorithm has detected a path that could be closed off-screen to create a loop -- but rather than being a (potential) loop around an island, it's a (potential) loop around a lake within a bigger piece of land.  So I need to modify the algorithm slightly to reject a path that encloses water rather than land.  As I've mentioned previously, my path-making algorithm always puts the water on the left-hand side of the path, so in this case, all I need to do is reject paths that run clockwise.

Here's another portion of that same map:
I'm not entirely sure I like the look when a number of islands in an area all get labeled; it gets a little busy and cluttered.  Let's take a look at a map with lots of islands.  It turns out to be a mild problem to try to generate a map like this; Dragons Abound has some safeguards that try not to generate maps that are mostly ocean (because those are likely boring) so I have to do some tweaking to get the right parameters in place:
Overall, this is surprisingly non-terrible.  :-)  There are a few obvious problems.  The label for the big island ("Chinsom Isle") looks out-of-place -- I think a human map-maker would certainly put it along the south side of the island.  For reasons that are not obvious to me, the label for "Amtun Island" clashes with another label and crosses the island.  There's clearly room below the island for the label, so I'm not sure why it is placed as it is.  Most of the rest of the labels are pretty well placed.

Of course, placing island labels on a crowded map can be challenging even for good map-makers:
This map has better placement than Dragons Abound can manage but it still has a few problematic spots.  Still, it suggest a few improvements to the way I'm doing island label placement, so in the next post I'll see if I can tune up my island labels a bit.

Tuesday, October 24, 2017

Labeling Islands (Part One)

I'm going to move on (temporarily) from labeling coastal features, and start labeling islands -- or at least groups of islands.  Dragons Abound has a couple of different ways to generate groups of islands.  Some are based on cones (volcano islands, like Hawaii) while others are just noise-based splotches.  In either case, they are generated as a clustered group of individual islands, although sometimes they overlap and run together.

My initial notion for labeling these island groups is to draw a path around the entire island group and then attach a path label for the islands to that path.  To do that, I need to keep track of all the islands in a group as I create them and then create a convex hull from those points.  In simple terms, a convex hull is just the minimal line that you can draw around a set of points if you are only allowed to draw from point to point.  It turns out that d3 has a function to calculate the convex hull from a set of points, so it's only a few minutes work to add this to Dragons Abound:
The green line here is the convex hull drawn around the islands.  The "Group Islands" label has been attached to this path and placed by the simulated annealing algorithm.  The only complexity is setting the offset properly so that the label will fall on the outside of the path.

Here's another example:
Note that in this case "Nun-Bun" was not included, since it was created by a different part of the terrain generation.

Here's an example where it doesn't work very well:
There are a couple of problems here.  First, some of the islands included in the group appear to be off-screen.  Second, the area for the group seems to be too large to look good as a "group".  The first part is easy to fix by adjusting the algorithm that places the islands to avoid any location that won't appear onscreen:
The second problem is that the total radius for a group of islands of this type (these happen to be "cone" islands like volcanoes would produce) is set too large.  Again, it's easy enough to put in a more reasonable range:
Here's another broken example:
For some reason, the island group includes a good chunk of land.  What happened here?  Generating the map without the islands makes it obvious:
The islands happened to get generated close enough to the shore (and other existing islands) to fill in and become part of the land.  I can address that by forcing islands to be further off-shore:
A final optimization is to make these labels prefer to be at an angle near zero.  This effectively tries to place them either above or below the island group.
Some differences here due to me tweaking the island creation algorithm, but you can see that the label has migrated to be underneath the island group.

And that's about all that's necessary to label the island groups.  The functions I'd built up for labeling rivers and coastlines provided almost everything I needed "out of the box" and with a few tweaks looks pretty good.  Next I'll look at labeling individual islands, like the two above the "Lost Coast" label in the above image.

Friday, October 13, 2017

Labeling the Coast (Part Three)

When I started working on labeling the coast, I was inspired by examples like these:
One idea I really like is to label a stretch of empty coast with an evocative name like "The Lost Shores" to create a sense of mystery -- why is this shoreline empty?  What keeps people away from here?  So now that I have coastline labels working, let me try to create that sort of an area.

The obvious approach is to search for an empty stretch of coastline and anchor a label there.  Right now the only features of interest on the map are cities, so this basically comes down to finding the spot on the coast that is the furthest from any city.  Here's an example:
On this map, the emptiest spot on the coast is midway between the cities of "Lorchler" and "Zhirsolchot".  However, this isn't entirely satisfactory because that stretch isn't particularly long -- about the same as the distances between the other coast cities.  In fact, most settled maps aren't going to have a lot of space between coastal cities because the coast is prime territory for settling, and cities end up being about as close together as possible.  (Except on maps where the coast is a desert, for example.)

So if I want stretches of empty coast, I'm going to have to intentionally create it.  This shouldn't be too hard -- it's really just a matter of eliminating a city or two along the coast.  For example, if I took out "Zhirsolchot" on the above map, there'd be a nice long stretch of empty coastline.  So I'll try picking an arbitrary spot on the coastline and making it off-limits for city building:
The addition of a Lost Coast tends to make the map more crowded because it essentially reduces the amount of usable area for cities and territories.  To compensate for that, I reduce the number of cities to be generated when a Lost Coast is created.

Here's another example picking a different random location:
When the label is near a map edge it creates a nice effect, tying the mystery of the Lost Coast to the mystery about what lies off the edge of the map.  But this placement is problematic because it's in a little bay -- which not only causes the label to cross the coastline, but it's also going to be a problem when I'm naming bays.  So I'll add a heuristic that tries to place Lost Coast labels along flatter parts of the coast:
This seems to work pretty well.  Here's another example:
This map has a kind of interesting placement for the label, inside a very deep "bay" -- deeper than my simple heuristic can avoid.  This map also happens to show some snow/ice covered lands to the north, which happens infrequently.

In the next posting, I'll move on to using coast labeling for some other purposes.

Sunday, October 8, 2017

Recreating a Style

While working on another feature I was looking at Western Torfani, one of my favorite maps:
I've learned a lot from this map, and I was curious to see how close Dragons Abound could recreate this style at this point.  I'd done this once before for a blog post but hadn't kept track of the settings I used, so I decided to try again and see how I could do.

There are a number of differences between Western Torfani and the default style I've been using lately:
Most obviously the land and ocean colors are quite different.  I can sample the colors from the Western Torfani map and force my program to use the same colors.  The same goes for the forests.  I can't quite match the ocean texture pattern at the moment but I can use a similar texture.  (I actually had the same texture at one point, but I'm switching over to all vector textures and haven't yet duplicated this one.)  In the forests, the internal forest texture is darker in the Western Torfani map so I can darken that up on my map.  The Western Torfani map has a really lovely texture on the land, which I can't duplicate, but I can use mottling for at least some texture.  Although the Western Torfani map has some 3D elements (like the forests and the mountains) there is no faux 3-D shading so I can turn that off.   The mountains are quite different -- at a minimum, the Western Torfani mountains don't have snow caps or hashing in the shadow areas, use thinner lines, and are more crowded together.  Setting these styles gets me to here:
Better, but the labels here aren't right. 

The Western Torfani map is using one of the IM Fell fonts ("IM Fell DW Pica") for labeling, using the italics version for the city labels and the small caps version for the map feature labels.   I can sort-of recreate some of this; I already have the IM Fell fonts as an option, and the code has an untested capability to style different types of labels differently (i.e., make the city labels italic) but doesn't have the ability to use different fonts for different labels.  However, you can fake small caps using the SVG/CSS "font-variant" property.  This isn't quite as good as using a specifically designed small caps font, but it will work. 

The Western Torfani map also uses a dark gray color for labels.  My maps currently use black, but I can set the font color to the same dark gray.  The Western Torfani map lays out the labels for major features like bays and forests along the major axis of the feature.  My program doesn't currently have that capability, so I'll leave those labels as they are.

The Torfani map marks regions with heraldic shields (a nice touch!) which I cannot duplicate, so I'll leave the regions labeled by name.  The Torfani map doesn't show borders between the regions, so I'll turn off borders as well.

The Torfani map also uses larger and stronger "halos" to offset the labels; I can duplicate this but I think the halo effect is a bit too strong on the Torfani map, so I'll stick with my default settings there.

All of that gets me to here:
Comparing this to the Torfani map suggests that the mountain outlines are still too thick and, conversely, the river outlines too thin.
The Torfani map also uses a coast decoration I haven't seen before:  A single, thick, light-colored line off the coast.  I don't currently have this as an option, but my system for drawing lines off the coast is pretty flexible, so it shouldn't be too hard to generate something similar:
The Torfani map also has a forest feature I don't currently implement.  Instead of pulling back the forest to show rivers where they pass through, or hiding the rivers entirely, the map shows a sort of "disturbance" where the river passes through the forest:
I've occasionally seen similar decorations on other maps.  Here it is on Taneaphis, another of my favorite maps:
Dragons Abound can't currently do this, but it's a neat effect and since it appears on a number of my favorite maps, maybe it's something I should add!

To start with, I can turn off how rivers currently pass through forests, so that they just disappear underneath the forest:
Next, I need to find the portion of each river that is inside the boundaries of the forest.  To do this, I have to take the polyline that is the river and clip it to the polygon that is the forest.  I don't have a routine to do that sort of clipping, and off-hand I can't find one already written, so I have to write that myself.  

The dumb version is not too difficult.  I already have a routine that can tell if a point is inside a polygon.  So I just have to walk along the polyline and notice when the points are inside the forest polygon and then again when they're outside.  I save all the inside points, and along the way I calculate the actual point where the polyline enters and exits the polygon.  That gives me this:
That looks correct, so now I just have to draw an appropriate effect along that path.

It isn't entirely clear what the Western Torfani map is drawing along the hidden rivers, so I'll have to experiment.

One thing I can easily do is use the same kind of bumpy edge I do along the edge of the forest.  Since this is supposed to be a seam in the forest that seems like a reasonable idea; it should look like an edge of trees running along the river.  Here's an initial attempt:
This has some potential, but there are a few problems.  One is that the forest texture clashes with the river path.  This will be a problem no matter how I style the hidden river.  I can address this by not placing any texture near the river paths.  A simple version of this isn't too difficult to do:
The size and styling of the hidden river needs some tweaking to make it more obvious:
That looks ... okay.  Or maybe not.

Another thing I can easily do is draw a line along the river:
And I can give a little more substance to that line by making it start wide and narrow as it goes along:
I can't figure out exactly what the Western Torfani map is doing with the hidden rivers:
But it looks like some kind of messy line, basically.  I can do something similar-ish by combining bumps and lines:
That's not too terribly different.

The last thing I want to try to replicate with forests is the border drawn along the front edge of the forest to create a faux 3D effect:
This border area can be created by making another copy of the forest and shifting it in the appropriate direction:
Here I've just filled in with a dark shadow.  What I want to do is fill that with something a little more artistic.  To get a quick notion, I can fill it with a simple "tree trunk" like pattern:
This looks surprisingly good for such a simple approach.  But one problem is that, unlike shadows, offsetting this area in the X direction doesn't make any sense.  It's better to just offset in the Y direction.  An example makes this clearer:
Now the tree trunks don't stick out to the side.  The Torfani map uses rough circles filled with the forest color along this border.  Unfortunately, I can't use a straightforward SVG pattern to get the same effect because the pattern isn't aligned to the edge of the forest:
Although just by happy chance this pattern doesn't work too badly to give a sort of "scribbly" edge effect.  I can add the forest color behind this pattern and jiggle the edges so that it doesn't look so mechanical:
This isn't exactly the same as the Torfani map, but I think the overall look is pretty close.

Now let's see what can be done to adjust the Dragons Abound mountains to look more like Torfani.
There are a lot of options to tweak here, but I'll start off by making the mountains steeper and more jagged.
That's better but there are some problems.  In a number of cases, the shadow line is sweeping so far to the left that it's outside the outline of the mountain.  There's also a rogue white mountain hiding in the mix, that's typically the result of a bad color calculation.
The shape of the mountains could still use some work, but the colors are not right, so let's fix that first.  Dragons Abound normally takes the mountain colors from the underlying land, but the Torfani map uses a different shade for the mountains and the mountain shadows.  I have an option to set these colors, so let me use that:
The Torfani map uses a flat color to fill the shaded areas of the mountains, and by default Dragons Abound uses a gradient.  Oddly enough, it doesn't look like I ever implemented a flat fill for shading, but that's easy enough to add.
At this point there are still a few significant differences.  The Torfani mountains are much more "rugged" than the Dragons Abound mountains.  Second, the Torfani mountains have additional details on the lit side of the mountain that add a good amount of texture.  With some tweaking and various adjustments, I get this:
Here the shape of the mountains are closer to the Torfani mountains.  The Torfani mountains do some interesting things with shading -- both with adding small shading areas for interest and with how shading is distributed.  I like the effect very much, but I'm not going to spend any more time right now to try to replicate that.

The Torfani map has a number of features that Dragons Abound doesn't yet implement, such as cliffs, pine forests, bridges over rivers, land and  and city icons:
I'll get to some (or all) of these things eventually, but I don't want to tackle any of them for this exercise, so let's see how the real Torfani map compares to the Dragons Abound version:
That's far from perfect, but it's not too terrible, either.  Normally Dragons Abound doesn't put forests right up to mountains because it's impossible (or at least very difficult) to get that right.  But I can force it to do that, and in this case it doesn't look too bad.

Here's a full map in the Torfani style (click through for full size):

And just for fun, here's the same map in the "Old B&W" style (click through for full size):

If you look closely near the center of the map you'll see a river label on top of the forest with no river in sight.  In this style, the rivers are hidden in the forests, but the labeling routine doesn't realize that.  There are hundreds of these special cases where map features interact in unexpected ways.