Saturday, June 11, 2022

Cleanup Time

 With the map compass series done (at least for now) I'm going to take a break from dedicated development and spend some time on cleaning up the existing code.  I'd like to get to the point where I have a number of styles I can use to generate a map that will almost always produce an acceptable result.  There are a few major problems I need to address but most of the problems are fairly minor annoyances that just have to be beaten down one at a time like a whack-a-mole game.

For no particular reason I'll start with forests.  One style of forest that DA uses is called “forest masses" and draws forests as large clumps, as so:

One problem with this can be seen in the individual trees around the Toplant River at the top of the map.  These individual trees clumps shouldn't be used with the forest mass style; they're really intended to be outliers when the forest is drawn as individual trees.  That's a fairly easy fix.

The second problem is the texture of bumps inside the forest mass.  It has a couple of problems.  The bumps tend to line up in rough columns, and there are bumps close to the edge of the mass where they get clipped.  

I wrote this style of forest fairly early on, and the bump texture inside the forest masses is getting placed using a sort of perturbed grid.  Since then I've realized that a Poisson disc sampling is a better approach for filling an area in this way, and in fact I can reuse the basic approach I used for the Tolkien forest style.

Surprisingly, the borrowed code works on the first try.  I just have to tweak the distance between the bumps some to get a decent range of textures.
Pulling the bumps in from the edges of the woods is more problematic.  To do this requires “shrinking" the polygon in which I'm drawing the bumps.  Shrinking/expanding a polygon is a non-trivial problem, as I've discussed in these pages before.  In no wise should you consider writing this code yourself.  In this case, I'm going to try using the polygon-offset library from Alexander Milevski; it is partially based upon the Martinez library, which I have also recommended. 

There are many ways for polygon offsetting to fail, or at least to produce difficult results, such as numerous tiny polygon “islands."  Many of the failure modes have to do with sharp vertices close together -- like the bumps on the forest masses.  So rather than shrink those outlines and let every bump invite trouble, I'll shrink the “unbumped" original forest outlines.  This helps reduce the number of errors, but it doesn't entirely eliminate problems. So this is an area of the code where it is helpful to catch exceptions and route around the damage.

With that and some tuning of the shrinking distance, the bumps are kept from running off the edge of the forest:

There are several other options that control the look of this style forest, but they all seem to work fine.

I most often draw these sorts of forests pulled back to reveal the rivers, as above.  There is an option to draw forests with “hidden" rivers (they're not really hidden, just displayed differently).  Turning that on doesn't work.  There turn out to be a number of problems, mostly “code rot" where I've made changes but older code hasn't been updated (or not properly) to use the new code.  It takes quite a bit of time to run down all the problems, but eventually I have it working again: 

It's kind of a nice effect, looks like a fold in the forest where the river runs.

The ocean visualization is pretty solid, although there's a small bug that causes the ocean to vanish occasionally.  That's pretty easy to fix, and along the way I realized that a map with the ocean as blank space is actually a nice variant.

Here's an interesting problem:

The hills are being drawn in green.  At first it looks like hills are getting filled with the forest color instead of the land color, but on further investigation, that isn't the problem.  The color is a hard-coded value hold over from the Knurden-style map, where the land color is green.  It shouldn't be hard-coded in any case, so I'll make the color derive from the land color if it isn't otherwise specified.

That looks better.  I like the subtle shading on these mountains.

Dragons Abound also crashes fairly frequently when drawing mountains, so I decided to run down and correct some of these.  

The crash has something to do with the the “topline" of the mountain.  The topline is the entire outline of the mountain, and there's a function that tries to clean up the topline if for some reason the topline dips below the baseline of the mountain.  After some tracing, there seems to be a missing parameter in my configuration file, and that causes the topline to get created incorrectly in one case.  I replaced the default value of missing parameter and that fixed the error.  I didn't see any problems in the resulting mountains, so apparently the default value is good enough.  I'm not sure why I had commented it out.

Here's a problem that popped up while I was working on labels:
In the upper part of this image, you can see a bay outlined in gray and labeled “Turquoise Point."  DA has mis-identified the bay as a point.  The primary difference between a bay and a point is that a point has land between the two end points of the green line and a bay has water.  Since there's clearly water between the end points of the green line, something has gone wrong.

This turns out to take nearly a full day of debugging to fix.  The details are complex, but the basic problem has to do with how to tell whether an arbitrary point on the map is in the ocean or in the land.  What makes this complex is that although the general shape of the land is created with a procedural generation algorithm operating on an underlying Voronoi graph, the final coastlines can vary from that for any number of reasons.  The two ends of Turquoise “Point" above are across a small bit of ocean that actually has some land in it -- you can see a small island.  And this was confusing the algorithm.

After no small amount of thrashing around I have a new algorithm that checks for land based upon the actual coastlines as drawn, and that fixes that particular problem:
Now there's no longer the spurious Turquoise Point.  There's now a legitimate point on the far side of the bay -- Dusky Point -- but there's a problem with the label.  That's discussed and fixed in the blog post on labels.

Another problem that popped up while working on labels:
This problem is somewhat similar to the problem with Turquoise Point.  It happens because the Voronoi tiles that make up the map are considered land if any part of the tile is above sea level. In places like this little strait, most of the tiles underneath it have at least one corner on the land, so to the forest algorithm, it all looks like land.  The solution is to use a stricter definition of land which requires the midpoint of the tile to be on land.  
There's still some small overlaps where the rounded edges of the forest intrude on the ocean, but that's fine.

Then there's this:
Bloody hell.  I won't be using that random seed again!  

(More seriously, this is some sort of problem with the polygons that define the forest masses but it seems to be a rare error.  I'll give it more serious consideration if it continues to pop up.)

Next posting I'll switch over to labels as mentioned above.


  1. I'm amused by the polygon bug because I get something similar occasionally - the polygons I use to create continents sometimes go haywire and I get long straight coastlines. I think it's something to do with applying a fill outside the boundaries of the polygon instead of inside it, but it's rare enough not to warrant spending too much time worrying about it. Polygons can be more annoying than you'd think!

  2. Indeed. Particularly when they're not well-behaved convex polygons!