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.

Wednesday, December 27, 2017

City Symbols (Part 5): Larger Buildings

In this series I'm working on procedural generation of map icons to represent cities.  So far I've been focused on generating simple houses:
Now I'm going to look at generating some larger buildings.

One obvious option is just to increase the size of my small buildings by making them wider.  This actually works fairly well:

although obviously the buildings created this way share a lot of visual elements with the small houses.

Another approach is multiple story buildings.  Most of the building blocks are in place for multi-story buildings -- it's mostly a matter of lifting the roof up and sticking in more basic building shapes for the additional stories.  Obviously I don't want doors in the upper floors, and I suspect that having the same window placement in the upper stories will look better than random windows.

Here's a first cut at a two story building:
It's basically just a one story building with the story height doubled.  That's because my code incorrectly assumes that the height of the building shape is also the height of one floor.  I need to separate those two numbers.
That's better.  Now I need to add the windows in to the upper floors.
Looks good.  I've added in some variation in the size of the windows.  Only a small amount so that they still look the same size, but enough to make them look a little more hand-drawn.

Tall buildings start to look like towers, so let me add a roof with battlements.   This is a low wall with gaps like teeth that are familiar from every child's castle drawing:
There's also the version where the battlement has been stepped out from wall to overhang the building.
A simple wall is just a house with a flat roof, and no windows or door:
These are more interesting when they have battlements:
Doorways in walls are a little different than the doors in houses.  I'd like these doorways to have the option to be open and show whatever is behind the wall.  To do that, I actually have to carve the door out of the wall, or I get something like this:
Here the door is not filled in, but the wall behind it still is.  So I'll carve the door out by removing the baseline between the sides of the door and substituting in the path of the door.
Now a castle of sorts is two towers with a wall between them.  Here's an initial cut:
This will probably continue to evolve, but you get the general idea.  Hopefully I'll be able to use all these building blocks together in interesting ways.

Sunday, December 17, 2017

City Symbols (Part 4): Faux 3D for Simple Houses

As of the last posting I had developed simple houses in a number of different styles.
Now I want to look at some 3D effects, such as seen in these city icons from the Western Torfani map:
In the Karambo city icon, you can see that some cylindrical buildings and the domed roofs have been shaded to give them a more 3D look.  And in the right city, you can see cast shadows on the ground and within the city itself.  These sorts of effects are called "Faux 3D" in Dragons Abound.

Let me start with the shading for cylindrical buildings.  At a minimum, that's just putting a dark band along the left side of the house.  I can create the shading band from the fill color of the house by reducing the luminance, although I don't want to use the same shade I'm using for the doors and windows.
You can see this is pretty crude, but at the map scale it's barely noticeable.  I can improve things with a little more elaboration.

Shrunken down to map size that looks pretty good.  SVG also offers linear gradients, so maybe I could take advantage of that.   We need a left-to-right gradient that mimics the layout we have above:

That actually looks pretty good.  I thought the linear gradient wouldn't work at the map scale, but it looks fine.  The colors are a little faded out to my eye, but not enough (at map scale) to worry about correcting.

(Note:  I later realized that the was a problem with the colors in the gradients and corrected this problem.)

Now let's see about giving the roofs a 3D effect.  Unfortunately, SVG doesn't offer exactly the right sorts of gradients to do this easily, but for domed roofs I can probably get by with using a radial gradient and treating the dome as a half of a sphere.

That doesn't look exactly right to my eye, but at the map scale it's certainly close enough.  

The peaked and flat roof styles look strange when combined with a cylindrical building, so I won't use those combinations.  But the eaved roof style (above) looks like a conical roof and I would like to be able to use it.  The gradient I need to do a conical roof correctly is a kind of "sunburst" gradient that pinches a linear gradient to the point at the top of the roof.  I don't think there's any way to do exactly that in SVG (let me know if I'm wrong about that), but I can do a crude approximation using a linear gradient that has been rotated to approximately the pitch of the roof.
I've used some artistic license here in not matching up the gradients exactly, because when I do that the roof and the building blend together too much.  At any rate, I think this is "good enough" at the map scale.

Unfortunately, now that I've added 3D effects to the round houses, the standard flat style doesn't look very good in comparison.  Which means that if I want to use 3D effects, I'll be limited to just round houses.  That doesn't seem acceptable, so let me go back and "3D" the standard houses.  An approach to doing this is illustrated in these icons from the Western Torfani map:
(I've blown this up to make the details more visible.)  In these examples, the foreshortened side of the house and the roof have been added. 

The house side is not too difficult.  I'm not bothering to do real perspective, so this is just a short parallelogram off the left side of the house.

And since this is the shadowed side of the house, it should be in the shadow color.  And for this type of roof ("peaked") the roof side is another parallelogram.
The "eaved" style of roof in 2D looks like this:
For 3D I'm going to make this into a pyramidal roof.  This is basically like the eaved roof above, except the roof side comes to the top center.
Since this roof overhangs the house, I'll add a shadow under the eaves.
The pagoda style roof is much the same, except with curved roof sides.
Now I want to add a shadow to the house.  I'm already doing shadows of this sort for mountains by reusing the outline of the mountain for the shadow but skewing it and filling it with a shadow color.  Unfortunately in this case I don't have the whole outline, but since the house is basically the roof and the body of the house I'll reuse those.

Transformations in SVG are always problematic for me because they are applied to the entire coordinate system, so skewing an object also moves it.  With mountains, I drew them at the origin of the coordinate system, which made transforming them easier but then required me to translate them afterwards.  For houses, I'm drawing where I want them, so the transformations are different.  After reading and re-reading some basic material, I eventually get the right incantation to skew and scale the shadow.  I also reduce the opacity and add some blur:

Here's what they look like on a map:
Next time I'll look at doing some larger buildings.

Monday, December 11, 2017

City Symbols (Part 3): Some Styles for Simple Houses

In the last posting I implemented simple houses to use for city icons:
One basic element I didn't get around to adding last time was a chimney.  This is just a rectangle sticking up off the roof line:
For these to look good at the map scale they have to be pretty sizable and have good separation from the roof peak.
It looks a little odd in a group like that, but of course normally I won't have a chimney on every house.
Here's a quick look at using these on the map to represent a small village:
Looks pretty good so far.  One thing I notice here is that it looks odd to have a house symbol overlapping the ocean (where the circle looks okay, compare Liel Luu above), so that's something I will have to address at some point.

These houses have some variation in things like the roof height, size and number of windows, etc., but they're basically all the same "style".  But I'd like to have houses of different styles, so that (for example) I can use different style city icons for different countries to visually hint at different cultures.

The first style variant I'll implement is pretty simple:  Adding eaves to the roof lines.  These are just little extra lines coming down from the roof:
These might look a little exaggerated but they're still only barely visible in the map view:
So maybe not a very effective styling, but at least easy to implement.  It might be better to fill in the eaves, like so:
This is more obvious than the other eaves style at map scale:
Another variation of peaked roofs is the "pagoda" style roof where the roof line is notably concave.  I'm doing semi-circles and arcs for a number of other things in Dragons Abound (such as labels and mountains) so it's pretty straightforward to replace the roof sides with arcs:
Notice that the arc has to be pretty exaggerated to be visible at the map scale.

Peaked roofs are an artifact of northern cultures where snow buildup is a problem.  In the Middle East and other climes where snow is rare flat or domed roofs are also common.   Since flat roofs are a little easier, I'll do those first.
The flat roof needs to have more thickness than the house outline so that it shows up at the map scale. 
A domed roof is created like the pagoda roof, but in this case using arcs that go outward:
Those roofs look a little crude because I'm only using 6 segments to render them.  But at the scale they'll be used in the map, this looks fine:
The tallest domed roofs start to look a bit like peaked roofs, so when using this style I'll probably reduce the possible height range of the roofs.

With domed roofs we should also have domed doors:
Unfortunately, these aren't really visible at the map scale (at least to my old eyes, YMMV):
Finally, domed roofs really should go on circular (cylindrical) houses.  This is mostly just a matter of changing the baseline of the house to be a curve.  This is surprisingly easy to do, since I already have the same code working to do the domes for the roof and the door.
You can see there are a couple of problems, though.  First, the door is floating because it still thinks it's on a straight baseline between the corners of the house.  Second, the flat line for the dome roof now looks wrong.  The windows should probably also lie along a curved arc, but I'm hoping this won't be necessary at map scale.

Fixing the door is a bit complicated but not too bad.  I need to extend the door downward and find the two points on the baseline where the door would hit. If I'm lucky, I'll be able to connect straight across those two points.  If I'm not lucky, I'll have to recreate the baseline curve between those two points.  Let's see if I'm lucky:
Looks fine, so I guess I'm lucky this time.  (Even if it didn't look good at this scale, it might have been fine at map scale.)  Now I need to do the same thing with the bottom part of the dome roof.  It's probably not necessary, but if we reduce the curvature along the top line it will make the perspective look more correct.
That improves things a lot, but now the straight line of windows does stand out.  Let's see how it looks at map scale:
It's not glaring but it does look odd on the houses with multiple windows.  In for a penny, in for a pound, as they say.  To fix the windows I need to offset them from the corresponding spot on the baseline, so this works something like fixing the door.
Well, it's not what I'd call fine art but it's serviceable.  Let's see what it looks like at scale:
To be honest, I'm not sure that's a significant improvement but maybe it helps a bit.

Up to now I've been using a basic red and black theme for the houses.  That has a certain appeal, but in general I think I want a more muted color scheme with less stark contrast.  To do this, I'll pick a fill color for the houses and then create the colors for doors, windows and outlines from that color.  Here's what that looks like:
This isn't very "artistic" but by using colors that vary only in luminance, the color scheme is guaranteed to work together.  And it means I only have to pick one house color.  Picking a color in the same family as the land or forest will also help the symbols to fit in well with the rest of the map.
One thing I did with mountains and other elements of the map is to create a hand-drawn look by jittering lines and adding some other line variations.  While I can certainly add this effect to these small houses, it is mostly unnoticeable unless the jitter is large enough to interfere with the drawing: 
The one element that does seem to work somewhat is varying the width of the line, which even at the small scale can introduce some interesting variation.

Next time I'll look at giving the houses a 3D look.