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.

Monday, October 2, 2017

A Different Way to Draw a Line

(Taking a break from labeling to talk about line drawing.)

Currently, Dragons Abound draws lines using the SVG path function, and then stroking the path with a pen of the appropriate size and color.  Combined with the D3js curve functions, this provides a pretty easy way to draw nice curved lines following a path:
I can use a different curve function to make a curvier or straighter line:
To make a line with varying width, I change the pen size as I draw the line:
By changing the pen size by small amounts, it gives a good illusion of a smoothly changing line size.

However, there are a couple of problems with this approach.  SVG doesn't allow you to change the pen size while drawing a path, so this is actually accomplished by breaking the path down into a lot of smaller paths, each of which is drawn separately with a different pen size.  If you don't have enough segments, the illusion doesn't work:
I handle this by interpolating the line into as many segments as I need, but this obviously results in a lot of complexity in the SVG.

A related problem occurs when drawing a curved line.  Because I start a new path every time the pen size changes, I'm usually not actually drawing a curved line but instead a lot of small straight segments.  This starts to become obvious when the path I'm drawing doesn't have enough segments:
If I don't change the pen size, this draws as a smooth curve.  But since I'm changing the pen size, I have to draw each piece of the curve separately and the result is a jagged curve unless I break the curve down into many pieces.

In working with Inkscape to develop vector drawings of sea monsters, I realized that Inkscape doesn't generally used lines (stroked paths) at all.  Instead, lines are created by using long thin polygons.  For example, a straight line would be drawn as rectangle around the path of the line:
If the orange dashed line represents the path, then to draw a line along that path, Inkscape creates the polygon shown as the thin black line, and then fills it in with the ink color.  If you want to make a line with varying width, you can just draw the polygon appropriately:
This approach avoids the problems I have with drawing varying width lines by varying the pen size.  There's no need to break the line down into segments to achieve a smooth curve -- I can use the SVG curve capabilities to draw each side of the polygon and get smooth curves that way.  The biggest drawback is that there doesn't seem to be a handy library available that implements this, so I'll have to implement it myself.

I'm not sure how this "should be" implemented, but I'm going to do something similar to the approach described here as Method 1.  I will start by finding the normal to each point along the path:
Then on each normal I will find the point on either side of the path that is half the width of the line at that point.  If this line gets wider from left to right, that might look like this:
The final step is to draw two smooth curves through the black points, connecting at the beginning and end of the line to create a closed polygon:
As you can see from this example, depending up on how "tight" or loose the side curves are, the resulting line will follow the path more or less closely:
I've had to calculate normals/gradients before, so this is actually pretty straightforward, and here's my first attempt, using straight lines between the points and drawing a constant width line:
Obviously not quite right.  It looks to me like the normals are incorrect.  Let me tweak the code to draw in the normals (exaggerated):
Hmm.  There's definitely a problem with the normals.  If the gradient is [dx, dy] then the normal is [-dy, dx].  I always forget the minus part of -dy.
That fixed some of the trouble but you can see that there's still a problem.  Some more fussing with the math and I have this:
Now you can see the normals look okay, but the width of the line is not correct.  Unfortunately, my simple-minded scheme doesn't work, because the angle of the normal changes the effective width of the line.  It's necessary to adjust the width of the line based upon the angle of the miter.  While working on this problem I discovered polyline-normals, a Javascript package by Matt DesLauriers that calculates both the normals and the necessary adjustment.  Dropping that in yields this:
Seems to be working!  Let's try it with a varying width line:
And finally, the same thing using curves instead of straight lines:

This looks pretty good, but you can see that the width isn't exactly right everywhere.  The difficulty is that the width is only specified at certain spots on the curve, and the interpolation in-between those spots varies for the top and the bottom curves of the line.  For mathematical reasons, it's very difficult to make the two curves match exactly, so this problem is somewhat inherent in this approach.  But if  you compare this result to the current approach:
You can see the advantage to being able to draw smooth curves even while the width changes.

As with the existing method, I can make the line width more faithful by increasing the number of points in the line:
I'm not sure this is actually an improvement; there's something artistically appealing in the more inaccurate less interpolated version.

How does this look when drawing map features?  First, let's look at a mountain drawn with the existing line routine:
Two things to note:  First, the ridge lines coming down from the two peaks are not smooth and very obviously connected line segments -- even though I'm trying to use smooth lines here.  Second, the short tapering line I've accented in red is jagged because the line size is changing in discrete chunks.

Here's the same mountain rendered with the new style lines:
Here you see that the ridge lines are much smoother and curvier, and the red line shows a much cleaner edge.  Of course, I don't have to use curvy lines with the new method -- you can see the mountain outline itself is still jagged -- but at least it allows that as an option.

I cleverly (luckily?) isolated all the line drawing in Dragons Abound behind an API, so I can seamlessly switch in the new line drawing routine.  Maybe I'll run into problems but at a first glance it seems to work just fine.