Even though most of Maperitive work I’m doing lately is done in a separate branch that will come out as a brand new Maperitive 2.0 release some time in the beginning of 2012, I do occasionally implement some quick enhancements to the currently “unofficially” released Maperitive beta. I’ve just uploaded a new beta version with a couple of neat features, one of which I will describe in this post (the other will have to wait for the next post).
This is an important, although probably not very well known feature Mapnik provides. What is subpixel accuracy? Simply put, it is the ability to set the thickness of the line in fractions of a pixel (image stolen from AGG’s site):
Up until now this was not really possible in Maperitive. Well, you could specify the thickness as, say, 1.3 pixels, but it would be rendered as a line with thickness of one pixel, ignoring the fraction. The reason is simple: Maperitive uses GDI+ library for rendering, which doesn’t do subpixel accuracy (it does support antialiasing, but that’s not enough). Mapnik, on the other hand, uses superior Anti-Grain Geometry (AGG) library (you can read more about it in AGG’s Introduction page, which is very interesting).
Why is subpixel accuracy important? Certain map features require delicacy. In his Cartographic Relief Presentation book Eduard Imhof gives very precise recommendations for elevation contour lines thicknesses. 0.05 to 0.08 mm for black normal contours for map scale 1 : 50,000, as an example. Without subpixel accuracy it is very difficult to come even close to such measures and then you end up with both normal and index contours (the thicker ones) having the same thickness in the rendering:
So given that I cannot directly render lines with subpixel accuracy and using AGG in Maperitive is not a practical solution because of various technical reasons I won’t go into, I’ve more or less given up on this.
… Until I came up with a simple but effective trick to achieve subpixel accuracy: render the whole map scaled to (say) three times and then downsample the whole image back to the “normal” scale. Before I delve into details, here’s how the same map looks like using this technique:
I think the difference is obvious: you can now see two distinctive contour line types. Index lines are 1.25 wide, while normal lines have a width of 0.65 pixels.Don’t worry about these numbers, subpixel accuracy is not that precise, but it is precise enough.
Subpixel accuracy can be tuned for three Maperitive commands:
All of them have a new
subpixel parameter which accepts a positive integer value. This value is used as a scaling factor when rendering. Once the rendering is done, Maperitive uses Supersampling algorithm to resample (downsample actually) the rendering to the scale factor of 1. So for example if you want to generate tiles using subpixel accuracy, you type in something like
generate-tiles minzoom=10 maxzoom=12 subpixel=3
What is the best value for
subpixel parameter, you may ask? I’ve been experimenting with the value of 3. You could try larger values, although I doubt there will be a noticeable increase in the quality of rendering. The downside of larger values is that Maperitive takes longer to render. This could considerably slow down your tiles generation, so there is a trade-off between the quality and speed (isn’t there always?). Measurements of tile generation speed show that by increasing
subpixel value by 1 halves the speed of tile generation. In future this should be mitigated by allowing Maperitive to render tiles using multiple processors.
You should also be aware that if you intend to use subpixel accuracy for exporting large bitmaps, Maperitive has to actually allocate a much bigger bitmap in the process of rendering. So for example if you want to create a 4000x4000 bitmap using
subpixel=3, Maperitive will want to allocate a 12000x12000 bitmap in the process and will probably fail due to limitations of GDI+ bitmap size. So there is no free lunch (at least until I figure a way around this problem ;) ).
One final note: interactive map does not use subpixel accuracy since this would make the map rendering pretty slow. In future versions Maperitive will provide some kind of “map quality” / “level of detail” setting, so you’ll be able to control this.