Per
Liedman

© 2016. All rights reserved.

Using TileMill Without Spherical Mercator

This text was originally posted on my previous employer's blog (Kartena), but since they've closed it down, I'm publishing it here as well.

TileMill is a fantastic design tool for styling maps. It is created by MapBox, it is free and open source.

At Kartena, we've been looking to replace our current styling and rendering pipeline for tiled maps for quite a while. There are plenty of shiny solutions out there (and quite a few less shiny, to be honest), but TileMill has always seemed like the best fit to our needs. Well, best fit except for one detail: TileMill officially only supports Spherical Mercator. Kartena mainly does maps for a Swedish audience, and many of our customers are government agencies, local transport organizations and so on. In these organizations, the local Swedish projections RT 90 and SWEREF 99 TM are de facto standards. Also, we're that far north that Mercator's distortion becomes quite visible in northern parts of Sweden, which just doesn't look right if you have a touch of design OCD. Luckily for us, you can actually trick TileMill into doing other projections than Spherical Mercator. I honestly don't know if this is by design from MapBox, or whether it's applicable to all projections, but at least it works well enough for RT 90 and SWEREF 99 TM if you can accept some hacking and UI weirdness.

Setting up the project's projection

The first step to get going is to set up the projection for your project. This change can't be done through TileMill's user interface, since it isn't really supported. You will have to hack the project's settings file manually. First locate your project's settings file. We're running TileMill as a service on Ubuntu, and the projects' files are stored under /usr/share/mapbox/project. Each project has its own directory, and the main project file has the extension mml. For example, our project LMV Bright has its project settings in /usr/share/mapbox/project/lmv-bright/project.mml. Open the project settings file in an editor. The file is JSON, and you're looking for the project's SRS (Spatial Reference System) declaration, which will look like this:
 "srs": "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over" 
The default definition is the PROJ.4 definition of EPSG:3857 / Spherical Mercator. By changing this line into the Proj.4 definition you want, TileMill (or Mapnik, which TileMill uses in the background, to be exact) will use your projection rendering your data. You can find the Proj.4 definition on Spatial Reference if you don't already have it.

Are we done?

Simple enough, ey? No, not really. If it were that easy, MapBox would of course have built in projection support and officially supported it. As Tom MacWright notes in the support answer referenced above, the details of tiling maps with projections other than spherical mercator is messy to say the least, mostly because there's simply no standard. What this means is that TileMill's map will continue to assume that Spherical Mercator is being used, and latitudes and longitudes will continue to show as if you were using Spherical Mercator. The underlying renderer, Mapnik, will however reproject according to the specified projection, since it has full projection support.

Why and how this works

In practice, this means that your data will show up in some weird part of the world, possibly very weirdly scaled. TileMill will assume your data's coordinates are spherical mercator and treat them as such when transforming them to latitudes and longitudes. For example, as can be seen in this image, TileMill's idea of Sweden's lat/lon bounds is completely off. Depending on your projection, the scales might also be very weird. In fact, I guess that for projections where the data ends up outside the projected coordinate space for spherical mercator, simply will not work at all. The result of this is that it might be a bit hard to first find your data, since it's easily lost in all the blue emptiness when you can't use the correct geographic coordinates.

Caveats

For RT 90 and SWEREF 99 TM, these issues are minor in our experience. You have to know that these issues exist and it's a bit tricky when starting, but once you get used to it, it is actually no issue at all. One important point here is that both RT 90 and SWEREF 99 TM use meters as units; so does spherical mercator, or at least pseudo-meters. This means that the scales for different zoom levels in spherical mercator matches reasonably with the scales you would use in RT 90/SWEREF 99 TM. I guess that this could be a real issue for projections with other units, although we have no experience with that. Also, all forms of tile export that is built into TileMill will be more or less broken when working like this. The tiles and lat/lon mapping will be equally weird for exported tiles as they are when shown inside TileMill. Theoretically I guess you could compensate for when using the tiles, but just thinking about it gives me a headache. Would not recommend it. MBTiles is an attractive MapBox/TileMill feature for creating portable tile sets, but it also explicitly does not support anything but spherical mercator. Extending it with projection support is on my (pretty long) list of things I wish I had time for.

Exporting tiles

So, why would you use TileMill if you can't export tiles from it? Well, you can export tiles, but you have to do it manually, or at least know how to use other tools for it. As already mentioned, TileMill uses Mapnik in the background to render the tiles, and Mapnik has fullblown projection support. The trick is to export the Mapnik XML from TileMill, and then use Mapnik directly to render the actual tiles. At Kartena, we do this with our tile cache, TileStache, which can use Mapnik to render tiles. Since we've extended TileStache with projection support, this works entirely as expected. Details on how to set that up is the topic for another blog post though. Mapnik is very friendly to integration, so you can also do this in a myriad of other fashions, if you like.

Proof of concept

Ok finally, to show you that this isn't just empty talk, here's a demo of two layers styled in TileMill, using SWEREF 99 TM (ESPG:3006) projection. Have you done something similar with TileMill or have questions? We're eager to here from you in the comments below.

Comments or feedback to this post?

I'm @liedman on Twitter or send an e-mail to per@liedman.net.