Monday, September 24, 2018

Grasslands (Part 5)

So far I completed the little “tuft of grass" marking and implemented at least a rudimentary display on the map.  Part of the challenge in using the tuft of grass mark on the map is that it's fairly intrusive if used widely.  It looks much better in a small area of the map.  So I'd like to try creating a new grasslands marking that might be more subtle.

An example of the kind of effect I'd like to achieve can be seen on this map of Middle Earth by Misty Bee:
This is quite a lovely map, so it's easy to overlook the faint horizontal dotted lines that fill the empty spaces.  They add interest to the empty space without distracting from the other map elements.

Here's another example, from a map of Romania by Cartographer's Guild user Kasey:
I'm not exactly sure what the small square bumps on the lines are supposed to indicate, but once again you see the faint line motif to indicate open land.

Drawing a horizontal line is pretty straightforward, so I can start with just drawing lines where I would have drawn the grass symbols:
One drawback of using the computer display is that you can't drawn infinitely thin lines -- in the end a single pixel is the limit of your resolution.  So it's impossible for me to get lines as thin as those on (say) the Romania map above.  That aside, these lines could probably use a little variation so they're all not perfectly horizontal, and probably be spread out more as well.
Here I've also turned off the grass coloring and spread out the grass symbols to cover all the land area.  This isn't awful but doesn't add much either.  Let me try the dotted line version and see how that looks.

For dotted borders I use SVG dash arrays.  Dash arrays are very flexible, but can only be applied to a path, so if I use this I'll be limited to a single width, color, etc., at least within one line.  Still it should be fairly quick to implement and see if it has any potential.  Here's a simple first effort:
The lines in the Middle Earth map above are more closely spaced, faded and varied, so let me try to add (some) of that.
This is not too bad.  It would probably benefit from some “hand-drawn" embellishments like jitter, but I'm not sure I'll use this enough to warrant the effort.  If I find that I'm using it a lot I'll go back and work on it some more.

Here's a variant where instead of making regular dotted lines, I'll make the dashes get bigger in the middle and smaller near the ends:
Visually it doesn't look a lot different.

In the meantime, let's see how it looks with the isolated grasslands style:
That's not terrible.  Here's the same style but with the lines more thickly placed:
This seems acceptable.

It's also interesting to combine the two styles, so that you have lines for the low grass and hachures for the deep grass:

That about wraps up illustrating grasslands (at least for now).  My general conclusions are that grassland markings work best when they are limited and/or use a subtle indicator.  However, there's a danger that marking only some grasslands implies that other areas are deserts, particularly for maps that use a brown color for land.  Distinguishing “deep grasslands" from “prairie" adds interest to the map (at least in my opinion).

Next time I'll look at modifying the grass symbol to create a symbol for marking swamps.


Monday, September 17, 2018

Grasslands (Part 3)

(Note:  This was actually posted out of order with #4.)

At the end of the last posting, I had a basic grassland/swamp symbol working, and was able to place it on the map in a reasonable way.  The basic symbol looks like this:
In this posting I'll look at adding some variation/interest to the generation of the symbol.

The first step is to vary the size of the symbol to be wider or narrower and have fewer or more “blades" of grass.  If you examine this example use:
you can see that the individual symbols have anywhere from three to ten blades.  There are a couple of ways I could program this variation.  I could pick a random width and then figure out how many blades could fit, or I could pick the number of blades and let that determine the width.  Either choice will be made more complicated if I allow the size of the blades and the gap between them to vary.  At any rate, I chose to pick a random number of blades and then let that determine the width.
The number of blades is chosen at random.  But a random distribution -- where every number of blades is equally likely -- is probably not the most realistic/artistic.  A better distribution would be weighted toward the middle of the range, so if I allow (say) 3-8 blades, most of the clumps will be 5 or 6.
I can also add some variation to the arch of each clump.
(I don't want to let the bottom get completely flat, since that will be the basis for the marsh symbol.)

Another tweak is to make the top curve a little asymmetric.  This is accomplished by moving the control point of the Bezier curve a little bit off-center.
As you can see, a few of the symbols now have a bit of a sway to the right or the left.

Likewise, I can tweak the individual blades a bit to either side so the spacing isn't quite so mechanical.
This has a pretty big impact on making the symbols look more hand-drawn.  If you compare the map-sized symbols in this picture with the one above you'll see that the ones above look much more mechanical.

I can vary the line width in a similar way.
Here I'm just varying the starting width of the stroke -- they all taper off to zero.

Finally, I can make the individual blades a little shorter or longer on either end.
The last (?) thing I'll do is add a little arc to the blades.  This is probably overkill at map scale (not that overkill has ever stopped me before) but is at any rate easy enough to try out.  Bending the blades just requires turning the straight blade lines into arced ones using the same quadratic Bezier curve routine I've used previously.
Here I've just used the same offset for every blade.  Which is good for producing eyelashes but maybe not so good for grass.  I need to make the offset switch over at the middle of the icon, so that all the grass bends away from the middle.
I'm not using too much “bend" here but it does give the grass a more lifelike look.  Here's a side-by-side comparison between the original symbols and the “hand-drawn" symbols:
Next time (actually last time) I'll take a look at using these symbols on the map.

Wednesday, September 12, 2018

Grasslands (Part 4)

Last time I finished up the basic generation of grassland symbols, which looked like this:
Now I'm going to look at placing these on the map.

Previously I made an initial pass at placing these symbols on the map, and had something like this:
In the upper part of the image I just placed symbols throughout the grasslands.  But that ends up clashing with a lot of other map elements; in the bottom half I added some code to make the grassland symbols avoid forests, mountains, rivers and coastlines.

Here's an example of a map using the more hand-drawn symbols:
The changes I've made to make the symbols more hand-drawn help quite a bit, but I find the overall effect to be cluttered and unappealing when applied over the entire map.  This is probably one reason you rarely see it used this way by human map-makers.

One way to address this is to reduce the visual impact of the grassland symbols by coloring them to match the land and reducing their opacity:
This ends up looking like a land texture.  This is an improvement and a useful option, but I still don't like the overall look.

The real problem here is having the same symbols over most of the map.  Generally speaking, I think the best fantasy maps have a lot of variety, so that every spot on the map looks like there's something interesting happening there -- not just a repeat of stuff that is everywhere else on the map.  And visually, if you have something happening over most of the map, it's better to leave that blank (background) to not distract from where things are different.

I can think of a couple of ways to reduce the amount of grasslands in an interesting way.  The easiest is to avoid putting symbols near cities.  The idea here is that the areas furthest away from the cities are the unsettled, more wild areas of the map, so we'll use the grasslands symbol to indicate that.
I'm doing something pretty simple here -- just eliminating grassland within a fixed distance of a city.  This works pretty well to make the grass more sparse and the map more interesting.  It also has a couple of drawbacks.  It's hard to pick a fixed distance that works well on all maps.  And it treats all cities the same way, where big cities probably should push back the wilderness more than smaller cities.  In the long run, I plan to have something in the world generation that decides what is really wilderness and what is settled.

I've colored the land green for these illustrations, but it's interesting to look at a map with a traditional brown land color:
This has quite a different feel to it.  To me, adding the grassland symbols causes me to see all the tan land as desert or wasteland.  Making the symbols green isn't any better:
Most of the reference maps I have that use this kind of marking for grasslands are black and white, or have a green land color, probably to avoid this problem.

I have a few example maps that use color to indicate biomes (i.e., grasslands versus desert).  I haven't done a lot with coloring the map to reflect the biomes, but I do have a simple version implemented that I use primarily for debugging.  It just fills in light green for grass, yellow for desert, dark green for forests, and so on.  If I turn that on and use the grassland symbols it looks like this:
It's nice to have a clear differentiation between the biomes on the map, especially where deserts meet the grassland.  On the other hand, deserts are actually fairly rare, so it isn't every map that will have a nice differentiation like this one.  But a problem with putting biomes on the map like this is that there's plenty of grasslands biome that doesn't get symbols, because I'm still avoiding putting grassland symbols where they would clash with rivers, the coast and etc.  As an alternative, I can  apply the biome coloring only where there's a grasslands symbol:
This looks pretty good, although it still has the problem that marking grassland in this way makes it seem as if everything else on the map is desert.  I'll continue to experiment with this and see if I can find some more appealing approaches.

Meanwhile, I can look at some variants for the grassland symbol.  One variant is to increase the height of all the blades, to make the tuft more leggy:
The opposite variant is to take away all the arc in the blades and make all the blades the same length:
These short straight tufts is an approach I've seen some human map-makers use.  I think both of these variants look pretty good.

That's basically all for this kind of grass symbol; next time I look at marking grasslands with a different sort of symbol.

Wednesday, September 5, 2018

Grasslands (Part 2)

This post I'll be working on generating graphics to represent plains or swamps that look like these hash marks:
It turns out I've already done something like this before, when I generated something similar to implement hachures.   That word might not be familiar, but you'll recognize hachures easily enough -- they are the curved hashes used to illustrate elevation, as in the two hills on this map excerpt:
If you compare these hachures to the field symbols above, you'll see the similarities.  To generate hachures, I created a curve, calculated the normal to the curve at various points, and then drew various length lines along the normals.  That worked fine, although I could never really get hachures to look good on the map, so I ended up discarding that code.

With some of the code I've written since hachures I have an easier way to generate these sorts of symbols.  I can create two different curves between the same end points, split each curve into an equal number of points, and then draw hash lines between matching points:
That's a mockup, let's work on the real thing.  The first step is the two outer curves.  In this case I'm going to use a quadratic curve -- this is a type of Bezier curve with one control point.  To create a symmetrical curve with height H, you place the control point above the center of the curve at twice the height H:
Once you have the start and end points and the control point, you can use the equation provided here to generate points along the curve.  This is a parametric equation -- the input is a number from 0 to 1 which represents the percentage along the curve, and the output is the point on the curve at that (percentage) location.  So it's very easy to use this to generate some number of points along this curve, as I need to do in this case.  All together, the code looks like this:

// See
// https://stackoverflow.com/questions/5634460/quadratic-b%C3%A9zier-curve-calculate-points
// t = [0, 1]
function calcQuadBPoint(start, control, end, t) {
    const x = (1 - t) * (1 - t) * start[0] + 2 * (1 - t) * t * control[0] + t * t * end[0];
    const y = (1 - t) * (1 - t) * start[1] + 2 * (1 - t) * t * control[1] + t * t * end[1];
    return [x, y];
};

// Make a quadratic arc from pt1 to pt2 that rises to a point h above
// the midpoint, and return it as a polyline with num points.
function makeQuadraticArc(pt1, pt2, h, num) {
    // Calculate the control point
    const x1 = pt1[0];
    const x2 = pt2[0];
    const y1 = pt1[1];
    const y2 = pt2[1];
    const cx = (x1 + x2)/2;
    const cy = (y1 + y2)/2;
    const dx = (x2 - x1)/2;
    const dy = (y2 - y1)/2;
    const dd = Math.sqrt(dx*dx+dy*dy);
    const ex = cx + (dy/dd)*h*2;
    const ey = cy - (dx/dd)*h*2;
    const cp = [ex, ey];
    const result = [];
    for(let i=0;i<num;i++) {
 result.push(calcQuadBPoint(pt1, cp, pt2, (i/(num-1))));
    };
    return result;
};

(This code should work for any start and end point; if you just need to do it for an axis-aligned arc like I'm doing here the code can be simplified.)

So I can use that to draw two curves between the same points, one a little higher than the other.
Looks good so far.  In this case, I don't actually want the curves, I want points along the curve.  So let me draw points corresponding to where the lines would go:
This shows a problem -- if I draw lines between the points, the lines will all be vertical!  How did that happen?  If the curves are split into equal-sized pieces, the points on the top curve should be spread further apart (because that curve is longer).

Well, it turns out that the parametric function above is not linear.  The points it generates will not be equally spaced along the curve -- basically the points are farther apart where the curve is steep and closer together where the curve is shallow.  The result is that the points line up even when they're taken from different curves, as I'm doing.  

So how do you get equally spaced points?  That turns out to be hard.  The most practical approach is to sample a bunch of points along the curve (say, 100), calculate the distance between the points, and then resample to find points that are equally spaced.  But that's a lot of work to draw a clump of grass.

What I need to do is either spread out the intervals around the center on the top curve or compact them on the bottom curve.  As it turns out, d3 has functions that do just this -- they take numbers on a range of 0 to 1 and remap them to the same range but with different intervals.  They're called easing functions.  Maybe I can pick an easing function that will do what I need.  The idea is to put the input for the parametric function through the easing function before using it for the upper curve.  So for example, if I'm generating the point for 0.25 on the bottom curve, I'll use the easing function on 0.25 to get a new value -- say, 0.17 -- and then use that for the upper curve.

For this to work, I need an easing function that “slows down" values before 0.5, and “speeds up" values after 0.5.  After some playing around trying out various easing functions, here is d3.easePolyInOut with an exponent of 1.5:
This does what I want -- the points on the top curve are now spread out.  And now the lines will fall away from the center outward.  Higher exponents to this easing function make the lines fall away faster.

Now I will stop drawing the top and bottom line and the points and just draw lines between the points.
And that's the basic shape.  It even looks pretty good just like this at map scale.

Before I go any further, I want to add the code to display the symbol on the map to get a sense of how it looks and refine the size.  It's always pretty challenging to get a nice placement of symbols in a case like this.  Obviously you want to spread out the symbols a bit so they don't overlap, and you want to scatter them in a more-or-less random way.  But you also have to take care to avoid a lot of the other map symbols.
The top image just places symbols into the grasslands and you can see this results in symbols clashing with the forest, the coast, rivers, cities and the mountains.  In the lower image I try to avoid all those things.  Before I place a symbol, I check it's distance to the nearest forest, mountain, etc., and skip it if that's too small.

Taking a look at this initial version, I'm not sure I like using this to denote all grasslands; there are a lot of grasslands on the typical map and this makes the map pretty busy.  We'll see.  Next time I'll work on making the symbol a bit more varied.

(N.B.A few weeks after writing this post, I realized I needed a little more control over the geometry of the hachures, and ended up changing the way I generate them.  The new method still has the same upper and lower curves to find the endpoints of the individual blades, but now the curves can be separated with some height (meaning the ends of the curves don't always touch) and the curves can be different lengths -- which eliminates the need to use an easing function.)