Wednesday, February 14, 2018

City Symbols (Part 10): Adding Features

In the previous two postings, I recreated the map icon style from the "Skies of Fire" map and then modified Dragons Abound to be able to use map icons on the map.  In this posting, I'm going to start adding the features I need to recreate the map icons from the "Torfani" map:
There are quite a size and variety of icons on this map, and I'm not going to attempt to recreate every detail of these obviously hand-drawn icons.  So it might be better to say that I'm creating icons inspired by these icons.

To start with, the icons are generally colored the same as the land color of the map, with a gray color for some roofs and shadows.  Generally speaking the houses are more squat than the "Skies of Fire" houses, and are given some shading for faux 3D look.  Adding those stylings to the "Skies of Fire" icons gives me this:
That's not very close to reference icons, but at least the colors are better.

The smallest icons on the Torfani map are typically two houses.  The same artist did a map called Domhantyr Orientalis that has some single house icons in it, but they always appear in the mountains and have an odd shape, so I suspect they're intended to be cave entrances.  At any rate, I'll concentrate on the two house icons on the Torfani map.  Here's a selection of them, at map size on top and then enlarged to make the details more visible:
There's a good mix of different styles and details here.  The most common version is a single house with a peaked roof in a 3D view.  The roof is uncolored (the same color as the house), the door is also not filled in, and there's sometimes a single window above the door.  The icons are also pretty small -- typically only about 5 pixels high for a "story".  Adding these constraints to Dragons Abound gets to this:
It's not clear to me whether it's totally intentional, but some of the roofs of the single houses on the Torfani map come to a single peak -- this is the "peaked" style of roof in Dragons Abound So I'll adjust the generation to get some peaked roofs in the mix.
Finally, some of the Torfani icons have small additional shapes sticking off the rear or side of the icons.  I can't really tell what these are intended to be, but they do add a little visual complexity and interest.  One way to do something similar is to add another small house behind the main house, and force the new house to have no roof, windows or doors -- in short, just a featureless cube.
That's probably (definitely?) overkill, but easy enough to add.
Next up are the medium-sized cities.  Some examples:
The medium-sized icons are not just more houses, but add some additional complexity.  First there's a mix of different house types.  There are square houses with peaked roofs as in the small cities, but also battlements and round houses with dome roofs and peaked roofs.  For the most part the buildings are in 3D view, but there is very little shading.  There's a mix of one and two story buildings (or at least short and tall), and adjacent buildings are usually different heights.  The icons are three buildings across in size, but there are sometimes towers sticking up "behind" the front buildings.  The buildings are all overlapped enough that you only see the side of the leftmost building.  It's difficult to be certain, but there seems to be some variation in baseline between the buildings -- that is, the bottoms of buildings further back are higher than the bottoms of nearer buildings.
It looks a little odd to have battlements or a dome on a single story house, so let me restrict those to the two stories houses.  Let me also add the possibility of a tower sticking up in the background.
The icon in the back row has a tower directly behind one of the front-row houses.  That looks odd, so let me add some logic so that the back row tower is between two front row houses.
That's good enough for the medium-sized icons.

Let's have a look at the major cities.

Once again, these icons aren't just a bigger version of the medium icon, but add new features.  On the building front, some interesting new towers have been added that seem to change sizes and have interesting bulges and decorations.  Some buildings and towers are flying pennants.  There's been some shading added to the buildings as well -- both shading on the individual buildings as well as shading out some of the buildings that are in the back of the city.  Finally, a wall has been added around the base of the city.  The wall follows (or defines) the contour of the city.  In some cases the wall is very tall and looks more like a mount that the city has been built upon.

Let me work on the towers first.  Before I get into trying to recreate the towers in the reference map, I'm going to create a couple of simple towers.

A tower in my system is just a skinny multi-story building.  So a default round "tower" looks like this:
An obvious refinement is have a tower that narrows towards the top.
The problem here is that the roof no longer matches up with the top of the tower.  So I need to re-write all the "roof" code to get the actual size of the top of the building, rather than assuming it is the same size as the bottom.  That turns out to be non-trivial, but gives this:
I made this work for rectangular buildings as well.  This was quite a bit more work because the roofs and the building have sides.  I'm not certain it was worth the effort, but it looks like this:
I probably don't have all of the combinations of roofs and overhangs and buildings quite right, but I'm not sure I'll even use square towers, so this seems sufficient.

There's another style of tower in the reference icons:
These towers have segments, and sometimes the upper segments get smaller.  This seems pretty straightforward for the 2D versions shown in these icons, but in faux-3D having stories of different sizes gets quite complex, with different bits of roof showing, the size of the sides of the house changing, etc.  This seems pretty intractable, but it occurs to me that I've implemented flat roofs, so maybe I can create a multi-story tower with changing sizes by stacking up buildings with flat roofs.  

There's a little bit of work involved to figure out how to place each building so that it appears to sit on top of the previous story.  Here's what it looks like with round buildings and each story getting a bit smaller:
I've adjusted the parameters for each story so that doors can only appear on the bottom floor.  One obvious problem is that the top floors are casting shadows in the wrong way.  Completely correcting this might be difficult, but a simple solution is just to turn off the cast shadows for the upper floors.

Here it is with that fix and using rectangular buildings:
This looks a little more awkward than with round buildings.

In the examples I generated above I stacked up three one-story buildings, but in the icons the tower segments look to be two or more stories individually.  That gives me this:
So that's a couple of different tower capabilities.  Next time I'll look at doing walls.





Tuesday, January 30, 2018

City Symbols (Part 9): Using City Icons on a Map

In the previous posting, I finished up creating the settings to make city icons like those used on the Skies of Fire map:
Now I'm going to talk about using these on a map.

Currently, Dragons Abound marks the locations of cities with circles:

Different size cities are indicated with different size and style of circles.  This is a very common map style, and has a lot of advantages when on procedurally generated maps.  It's easy to center the circles on a location, easy to calculate how close the label is to the circle, and it looks fine even when it overlaps the ocean or a map feature (like the symbols for "Bi en I" and "Ao Oiru" do in the map above).  

The procedurally-generation city icons, on the other hand, are relatively large and oddly shaped.  Sometimes they look fine on the map, as with these examples:
But often there are problems, as with these examples:

The icon in the upper left is floating out to sea (or more generally, interacting in a bad way with another map feature) while the icon in the lower right is colliding with it's own label.  The latter problem is a simple fix.  In the quick hack I did to add these icons to to the map, the labeling routine doesn't know that the icon is bigger than the small circle it expects, so I just have to add in a more correct size:
The other problem is more difficult.  The city icons are large and not uniformly shaped, so it seems inevitable that these will sometimes collide with other map elements in an unwelcome way.

However, I have one advantage that a real cartographer doesn't.  My maps don't have to reflect "reality."  Since I'm generating the entire map, I can choose not to generate a city in a place where the city icon would look bad!  There are a couple of ways to do this.

One approach would be to simply eliminate any city that had an icon problem.  But that might eliminate too many of the cities -- I don't want to unwittingly depopulate the map.

Another approach is to have rules during city generation that would avoid locations where the icon would look bad.  The difficulty with this approach is that at the time I'm generating the city locations I don't know how I'm going to be displaying them -- what kinds of icons or the sizes and shapes of the icons.  (And I want to keep generation and display separate.)  So the rules would need to be very general and conservative to work well. In the case of "Chuskoon" above I'd need to have a rule that keeps city locations far enough away from the coast that the biggest possible icon wouldn't stick out to sea.

Another approach is to wait until I'm going to display the cities, and then move any city location that is causing a problem.  In the case of "Chuskoon" above I'd slide the city location to the left until the actual icon I'm using no longer overlapped the ocean.  This would result in the minimal "fix" for each problematic city.  The challenge with this approach is that moving the city location might break other map features.  For example, if I've drawn a road between Chuskoon and another city, the road might now go to the wrong location.

Considering all these approaches, I'm inclined to use the last.  My intuition is that most fixes will only require moving the city a short distance, so the impact of moving the city should be minimal.  Also, with the relatively large icons, there's a good chance that the original location of the city will still be somewhere under the icon.  It doesn't really matter if a road comes into the Chuskoon icon at the lower left or the lower right.  So this should also help minimize this problem.

The question now is how to move the city location to fix any problems.  We have a desired location for the city location (the original location) and we want to find the closest nearby spot that meets the other criteria (not overlapping a map feature, etc.)...  Hey, this is sounding a lot like another problem!

In fact, this is the same as trying to find a good label location (although city locations will have different success criteria).  And there's no reason I can't run city locations at the same time as the label locations.  I'll just treat the city icons as "labels" that need to be placed on the map, with a strong preference to being near their original location.

So what criteria should I use when placing the city icons?  Consider these examples:
Here I have cases of city icons overlapping rivers, mountains and coastlines.  Most of these look fine to me.  The 7 building city near the bottom middle looks a little awkward on the river, but the other cities straddling rivers don't look as awkward.  A river passing behind a city (as with the other two cities at the bottom of the image) looks fine.  The icons that overlap upward into the ocean look fine.  The middle upper icon that overlaps a bay looks a little confusing, but is probably acceptable.

Here are some examples that don't work as well:
In each of these cases, part of the baseline of the icon is in the ocean.  It looks okay if the icon projects upward into the ocean, but it's not okay if the icon looks as if it is sitting in the ocean.

The reference map mostly follows similar rules, but breaks them in a few places:
In this excerpt there are icons overlapping mountains and rivers, as well as sticking up into the ocean.  But while most of the icons are placed to stay out of the ocean, a few like "Port Turio" have a foot in the ocean.

So it would appear that the most important criteria is to place the icon so that the baseline of the icon is entirely on land, while staying as close as possible to the original city location.  I'll also add a criteria to keep the icon on the screen.   After implementing that (and a frustrating couple of days debugging) I have this:
You can see that all of the cities have migrated onto the land, where they're generally snugged up against the coastline near the original city location.

One subtle problem this introduces is in the label for the city.  Now that cities can move around the map, the city labels need to follow them -- I can no longer tie the label to the original static city position.  For example, in the above map, you can see that "Nuochnir" has been placed close to the city's original location rather than it's final location.  To make the labels follow the cities around, I have to link the labels to the icons rather than a static point:
And now "Nuochnir" and "Nochboch" have migrated to better locations.

Here's what a full map looks like (click through for full-sized version):

Wednesday, January 24, 2018

City Symbols (Part 8): Recreating the "Skies of Fire" Style

There's more to be done on building styles, but at this point I have the basic functionality to recreate icons as used on one of my example maps:
Generally speaking there are two types of icons on the map:  city icons and fort icons.  The only significant difference between the types is that the city icons have peaked roofs and the fort icons have battlements.

I'll start by duplicating the look of a single building.  I'll set the fill color of the building to red and the roof color to black.  I'll use the simple "peaked" roof type and fill the roof with black.  I'll also adjust the size and width/height ratio to match.  I've isolated a few icons from the map for comparison:
I've shown the icons at both 250% and actual size.  The icons from the reference map are in the first column and my icons in the second column.  It's a pretty good match, although the outline is heavier on the map icons.  That's easily adjusted:
Now let me work on combining buildings to create icons.

The icons are essentially a line of buildings with some constraints.  Icons for small cities have two buildings; icons for medium-sized cities have five buildings; and icons for the largest size city (there is only one) have seven buildings.  In small cities there are two and three story buildings; in larger cities there are also four story buildings.  Adjacent buildings are never the same number of stories.  All the buildings in an icon have the same baseline, but adjacent buildings overlap by a small amount.

Combining buildings into an icon is basically just a matter of drawing multiple buildings.  But since I'm creating these buildings procedurally, I don't know everything about them ahead of time.  That creates some challenges with placing the buildings -- if I don't know how wide a building will be until I create it, then I don't know ahead of time where to place it to get (for example) a certain overlap with the next building.  Likewise, if I want to center the icon on a particular spot, I can't do that until I generate the entire icon and know it's width and height.  In general, I address these challenges by first creating the building or icon and then moving it to where it needs to be.  Fortunately this is fairly easy to do with an SVG transform.

But for the moment I'll just work on generating an icon that looks right.  Implementing the rules above gives me this first cut:
Here the icons from the reference map are on the left and my generated ones to the right.  Here's the same thing blown up a bit to make it a little easier to inspect:
I see a couple of problems.  First, the reference icons have wider buildings than my icons.  That's just an adjustment to the height/width ratio of my buildings.  Second, the reference icons also have more overlap between the buildings.  (I'm also overlapping strictly left-to-right, but I'll address that next.)  Again, that's just tweaking a constant.  Third, some of the example buildings have the "Witches Hat" roofs.  I'm not sure that's terribly important, but I do like the notion of having some occasional buildings that "break the style".  I'm not going to implement a Witches Hat roof, but I can use a pagoda roof to get a similar look (especially at map scale).  Fourth, I have some buildings with no windows or doors; that looks a little odd in this style of icon.  Finally, the example icons have some faux 3D shading as if they were round buildings.  Normally if I made my buildings round they would have curved bottom edges, but if I set the curvature to zero I get "round" buildings with flat bottoms, and then I can add in some shading.
And here it is blown up a bit:
That looks pretty close.  So now let me fix the overlapping to be less regular.

As with most computer graphics, the buildings in these icons are overlapped in the order they're drawn.  I draw them left to right, so each building overlaps the building to its left.  To make that overlapping random, I need to draw the buildings in a random order.  But that's a bit problematic because I don't know, for example, how far building #1 should be from building #5 until I've drawn the buildings in-between.  However, in SVG it's possible to reorder elements even after they've been drawn.  So after I create the icon I can go through and randomly raise some of the buildings to the top.
One thing I haven't done is add the small circle at the bottom of the icon to indicate the city's map location, so let's do that:
I think that's a pretty good recreation of the original map icons.  (I don't use fort icons on my maps (yet?) but generating fort icons is mostly just a matter of switching the roof type to "battlements".)

One enhancement that I see used on some maps is to add a heavier border around the outside of the icon.  To do this, I have to take the union of all the polygons that make up the icon and then draw the union in a heavier pen:
This makes the graphic a little more recognizable as an icon and also helps separate it out from the background.

Next time, I'll start looking at using these on a map.

Monday, January 15, 2018

City Symbols (Part 7): Faux 3D Redux

In a previous posting when I added faux 3D effects to simple houses, I didn't yet have a battlement roof like these:
So now let me add faux 3D effects to these kinds of roofs.  In my last posting, I fixed up round houses by using ellipses in the faux 3D view:
If I make the battlements follow the ellipse line and fill them with the same gradient, the front of the building looks fine.  Now I need to fix up the back of the battlement roof.  In the above picture, I've drawn in the basic ellipse for the back half of the roof.  Now I need to add battlements to that line.  This is basically the same as with the front part of the roof.
Here I've added battlements to the rear line.  But there are a couple of problems.  First of all, the gaps in the battlements (which are called crenels; the solid parts are called merlons) tend to line up between the front and rear since the two lines are the same length and the pattern is the same.  Second, since I'm forcing merlons at the sides of the building, I end up with a double-wide merlon at each side.  The solution is to reverse the "polarity" of the rear battlements and make it start with a crenel (gap) at either side:
Now I need to color in the back part of the roof.  Because the back is concave, it gets the opposite gradient from the convex front part.  There's no simple way in SVG to reverse a gradient, so I have to create a new reversed gradient myself.
There are still a couple of shortcomings here.  The roof is probably too "deep" -- we should be able to see a floor between the front and back.  And the walls themselves are just lines -- there's no depth to the battlements.  Neither problem shows up at map scale, though, so I can ignore them. :-)

The parapet style roof is like the battlement style, but it sticks out from the building.  (So that defenders can drop burning oil and the like on anyone at the walls of the building.)  Drawing this in faux 3D is much the same as for battlements.  The two differences are that I draw a line around the bottom of the parapet and I add a shadow underneath the parapet.
The shadow underneath the parapet is probably overkill at the map scale but I left it in anyway.

Doing battlements on square buildings turned out to be more challenging because there are three pieces to deal with.  There are left and right sides with slanted roof lines that are in the shadows and then a back wall that is lit.  With a routine to take a line and add crenels to it to create battlements, it's mostly a matter of bookkeeping to determine the four lines of the roof, the fill areas and sorting out the order to draw them.  That only took me a few hours :-).
Surprisingly enough (to me, anyway) parapets on square buildings fell into place without any additional work.
And here's what that looks like put together to create a "castle":
Note that the wall -- since it's really just a narrow building -- has picked up a second set of battlements, but the door remains just a piercing through the front of the wall.

Tuesday, January 9, 2018

City Symbols (Part 6): Fixing Some Problems

I'm going to pause development of the city symbols for a posting in order to address a couple of problems in the current implementation.



The first problem has to do with drawing lines.  Some time ago, I switched to a new method for drawing lines.  Rather than draw a line the traditional way (by moving a "pen" along a path), I draw a line by creating a polygon outline around the path, like this:

This has the advantage that I can change the width of the line.  In the example above, the width goes from near zero on the left to wide on the right.  I can then draw the line in a pleasing way by running a smooth curve (e.g., a series of Bezier curves) around the outline of the polygon.

Generally speaking this works very nicely and is a big improvement.  However, it sometimes runs into problems at the ends of the lines.  In the example above, notice that at the right end of the line, there are two sharp right-angle turns as the polygon goes around the end of the line.  If I'm drawing the outline of the polygon with straight lines this isn't a problem.  But if I'm using some sort of smooth curve, the curve might have to distort quite a bit to go smoothly around these turns.  This results in a bulge at the end of the line, as with this example:
Here I'm drawing an elliptical arc from left to right, and where the outline goes around the sharp turns the curve bulges out to smooth those angles.

Initially I addressed this by using straight lines to draw the polygon around the line.  As long as I use enough segments in the line, this looks fine, but that does eliminate one of the advantages of drawing lines this way.  

Somewhat belatedly, I realized that I don't have to use the same curve to draw the ends of the lines as I do for the rest of lines.  At the SVG level where the line is actually being drawn, I just need a connected path around the line; it doesn't all have to be similar curves.  So in theory I should be able to switch to a straight line for the small segment at the end of the line.

D3 -- which I use for most of my graphics -- doesn't seem to have a way to switch curves in the middle of a path without sticking in an extraneous M(ove) command.  (It might be possible to implement this form of line drawing with D3 Areas but it doesn't look like that's exactly right for arbitrary lines.)  So I have to generate the paths for the two sides of the line and the two ends separately and then stitch them together manually.  That's not terrible difficult to do:
And voila!  The problem is fixed.  This method creates a flat end to the line.  That can create an issue where two lines join, as is (barely) visible in this highly magnified example:
This often looks better if the lines have rounded ends.  Naively, you might think that this just requires connecting the two sides of the line with a semicircle rather than a straight line.  But doing that would actually cause the line to extend slightly (by the radius of the semicircle) past its endpoint.  To do this correctly, I have to back off the endpoint of the line by the radius of the semicircle and then connect it with a semicircle.  I'll leave this on the TODO list until it looks like I really need that capability.



The second problem has to do with how I'm drawing round houses like these:
I'm using a quadratic Bezier curve for the round parts of these houses.  This looks okay by itself, but a problem becomes apparent when I try to draw in the back half of one of these roofs:
The outline of the roof is too pointy at the ends -- it's a football when it should be an ellipse.  I should be drawing a (half-)ellipse for the round houses instead of the curve I'm using.

The curve-creating function I'm using is very handy because it allows me to specify the starting and ending points of a curve, and the height it should curve out at the midpoint and then step along the curve generating points at regular intervals.  Doing the same thing for an arbitrary ellipse turns out to be considerably more complex, but the case I need is a little simpler.  In my case, the ellipse is axis-aligned.  Consulting the Wolfram Alpha ellipse page, I find a parametric equation for points on an ellipse that looks like this:

`x = a*cos(t)+C_x`
`y = b*sin(t)+C_y`

In these equations a and b are the X and Y axises of the ellipse, t is an angle from the center of the ellipse, and `C_x` and `C_y` are the coordinates of the center of the ellipse.  Using this equation I can write a curve-creating function that produce half-ellipses between two axis-aligned points.  Substituting the new function into my building-drawing code gives me this:
That looks a little better.  Next time I'll fix up the faux 3D view for buildings with battlements and parapets.