Monday, November 27, 2017

Various Miscellany (Part 2)

Some current statistics (11/27/17):

    Source lines of code:  36271
    Dead/removed lines of code: 6559
    Number of configuration parameters: ~1700

The number of configuration variables is a bit misleading, since it includes specific configurations (e.g., to recreate a specific map style).  Still, there are a large number of parameters!


While generating maps on another topic, I noticed that I had some city labels colliding with the city icons, as in this example:
It may be a little hard to see because of the bounding boxes, but the city label "Homlunhan" is overlapping the icon for the city.  More importantly, you may be able to see that the bounding box for the text string (the purple box) is actually too short.

The key to this bug is that only the capital city with the large label has an incorrect bounding box. You can see that the smaller city "Kuhenpen" is fine.  As it turns out, there was a bug in the code that was causing the bounding box for capital cities to be computed with the font size of a smaller city, while the label itself was getting the correct size.  Once that was corrected, all was fine.


I returned recently to the problem of "holes" in the woods.  This happens when there is a large mass of woods and a bare spot in the middle, sometimes from mountains.  Polygons with holes inside of them are always problematic, and this situation created a lot of problems for Dragons Abound.  I had another long airplane flight and fixed most of these problems by carefully constructing the forest areas and letting SVG figure out the holes.  But there's one part I couldn't rely on SVG to calculate for me -- the "bumps" around the edge of the forest.  I create these myself by the process described here.  And it was sometimes the case with forest holes that the bumps faced the wrong way:


In this example, the bumps in the larger hole point inward instead of outward.

When I construct the outlines of the forest, I construct the path so that it runs clockwise. But that doesn't tell me which side of the path the forest is on, so the bumps sometimes go the wrong way. What I need to do is construct the path so that the forest is always on the left (or right) side as you go around the path clockwise (or counter-clockwise).  Then my bump can consistently go away from the forest mass.

But how do you tell if a point is on the left side or the right side of a line?
Is C on the left side or the right side of the line AB?  First of all, it depends on whether the line starts at A and ends at B, or starts at B and ends at A.  But let's say the line runs from A to B.  How do we know C is on the "left" side.

You might consider doing something like determining the angle between AC and AB, and seeing whether the angle is positive or negative:
But it turns out there's an easier solution.  You can use the cross product of the two vectors:

function isLeft(a, b, c) {
     return ((b.X - a.X)*(c.Y - a.Y) > (b.Y - a.Y)*(c.X - a.X));
};
This is positive when C is on one side of the line, and negative when it is on the other.  (Which is which depends upon your coordinate system.)

I can use this to make sure that I always construct the paths around the edges of my forest so that the forest is to the left of the path.  And then my bumps always go the right way:


When Dragons Abound creates a map, it randomly selects a font from a list of suitable fonts.  (The suitable fonts for a fantasy map are not the same as for a handwritten map.)  One persistent problem with this has been that the fonts seemed to display at different sizes.  Some fonts would be very big on the map while others would be tiny, even when I tried to display the at the same size.  Here are a variety of fonts displayed at "20px" size:
As you can see, there's a considerably difference in both height and width across the fonts.  My expectation when I set the size of the font to '20px' is that would result in the same height or the same width across the fonts.  (Because the aspect ratios are different between the fonts, the height and width can't both be the same.)  But in fact neither the height nor the width was the same.

This is pretty puzzling to me -- What does it mean to set the size of a font to "20 pixels" if that isn't the same across the different fonts?  I posted a question about this to Stackoverflow, and also to Reddit.  The answer is complicated but the TL;DR is that font sizes don't mean anything that's particularly useful.  They can be completely different from one font to the next.  This seems like madness to me, but there you go.  I've dealt with other maddening "features" in creating  Dragons Abound; I guess I'll deal with this.

My solution is to measure a sample text when I load up a font and then calculate a scaling factor to correct the font sizing.  By calculating a scaling factor for every font I use, I can make them appear to be relatively the same size.  I can't make both width and height the same.  Since the length of text is more important on the map than the height, I've chosen to make them all roughly the same length.

What should I use as a sample text?  Initially I used "ABCD...Zabcd...z".  But that's not really a good choice, because in English text, all the letters don't appear equally often.  For example, the letter 'E' appears about a hundred times more often than the letter 'Z'.  So if I want typical text to be close to the same length, I should care more about 'E' than about 'Z'.  To do that, I constructed a long text string that provides more copies of frequent letter than infrequent letters:
EEEEEEEEEEEEeeeeeeeeeeeeTTTTTTTTTtttttttttAAAAAAAAaaaaaaaa
OOOOOOOoooooooIIIIIIIiiiiiiiNNNNNNNnnnnnnnSSSSSSssssssRRRRRR
rrrrrrHHHHHHhhhhhhDDDDddddLLLLllllUUUuuuCCCcccMMMmmm
FFffYYyyWWwwGGggBbJjKkPpQqVvXxYyZz'
That may look a little silly, but it produces a better scaling factor than ABCD...  Here's the same font display with scaling to make the font height equal:
As expected, the sample text is still somewhat different lengths, but you can see that it is much closer now than without any scaling.  It's too bad CSS doesn't provide this capability, but this solution isn't too painful and gets close enough for my needs.

No comments:

Post a Comment