Saturday, August 20, 2011

Simple OpenStreetMap tile rendering with Maperitive

Lately there have been a lot of people popping into the OSM IRC channel (#osm on oftc.net) because they have been getting the "you've been bad" tile from the OSM tile server:


The reason is that they are using tile scraping applications that violate the OSM tile usage policy. Typically people just want to download tiles for their city or a vacation destination or travel route in order to pre-load them on a mobile device for offline use.

This is of course a perfect use case for OSM. The problem is that OSM is a project run by volunteers and with limited server capacity. Our primary product is geographic data, not map tiles. So when these tile scraping programs start hitting high zoom levels, it can cause serious problems for the tile server. The solution is to download OSM data instead of rendered tiles. Then you can render your own tiles or even use offline vector rendering.

One tool to make your own tiles is Maperitive. It is pretty easy to use and by default generates tiles that are fairly similar in style to the default mapnik style you see on osm.org although it is very customizable. It is a .NET application although it claims to work in Linux/OSX with mono. Also, while it is free to download, it is not open source which is kind of rare for the OSM world. These two things may cause some people to have an allergic reaction (I'm looking at you, Serge) but if you're still reading, here is a quick lesson on how to use it to render your own tiles. If you keep reading, you should be able to start rendering your own tiles in about 10 minutes. There is a tutorial video and some detailed documentation on the Maperitive website but I don't see a basic text based tutorial that walks you through the common "render some tiles for this area" use case.

Getting Started
Installation is pretty straightforward. Just head over to http://maperitive.net/ and find the "Download" link. Grab the latest .zip file (Maperitive-1228.zip right now) and download it. Once the download finishes, just unzip the Maperitive folder inside of the zip file somewhere and you're done. Open the Maperitive.exe file to fire it up.

Here is a screen shot of my Maperitive with some OSM data already loaded in. It should all make sense by the end of this post.

The first time you fire up Maperitive, you will notice there is already a map on the screen! By default it just starts loading map tiles from osm.org so you can get your bearings and navigate to an area of interest. Next, look at the bottom of the window. On the left is a text area (labeled "Commander" in the tab above it) where status messages and command outputs are displayed. Below that is a command line. This is a graphical program but a lot of the advanced functionality is done via this command line. A note about typing commands: Maperitive automatically completes commands for you which is nice... but it does it in a rather annoying way. As soon as you have typed enough for it to identify a unique command, it immediately fills in the rest of the command. I am much more used to a user-driven tab completion style as seen in most linux shells so the automatic completion in the middle of typing a command means my fingers keep typing the command after Maperitive auto-completes it for me and I have to backspace to erase extra characters.

On the right side is a "Sources" section that lists what map sources are currently being displayed in the main window. You can turn each one on and off by clicking the star by it. In the menus are various options. When you select one it will execute a command that you can see being executed in the Commander pane at the bottom. For example, find your home city and then go to the View menu and select "Set Home Location." You will see the text "> set-home" appear in the Commander. You can do the same thing by typing "set-home" in the command prompt and hitting enter. Now you can use the "Go Home" option to snap back to your "home" location from anywhere.

Selecting an area
Next, you must select an area of the world to render. You can navigate with your mouse just like on osm.org. Holding down shift while dragging with the mouse will draw a box. After you release the mouse button the view will zoom to that box. I'm not really sure what the limits of Maperitive are as far as volume of data. Note that the way it downloads data from the XAPI puts a limit of 10 square degrees on the download area. But this translates to a box of over 100 kilometers on a side and I'm guessing Maperitive will have a hard time with that much data anyway. I tried my county which is about 30x60 kilometers (18x37 miles). It contains about 26 MB of data in .osm format. I was able to render tiles on a 2.8 GHz Core i5 system down to zoom level 18 in about an hour with a memory footprint of under 300 MB. This should be a big enough example to cover many use cases so I will be using this area in my examples.

By default, Maperitive renders everything you see in the map on your screen. So if you are happy with that, you can go to the next step. To customize the area to something more specific than the shape of the window, read on.

You can set a more specific bounding box for all your operations by using the command prompt. One easy way to find a bounding box is to use the XAPI frontend. Browse the map and then hold shift while dragging the mouse to draw a box. After drawing the box, check the "Search by Area" checkbox above the map. Now look down at the bottom of the page and copy the latitude/longitude coordinates after "bbox=" - in my case: -96.964,39.025,-96.547,39.573 (do NOT copy the ] at the end!)

Now go back to Maperitive and use the bounds-set command:
bounds-set -96.964,39.025,-96.547,39.573
Maperitive will reply with "Locking the bounds to ..." and will draw a thick dotted line on the map to show the bounding box you have selected. It is clearly visible in the screenshot up above.

Downloading data
Now that you have your area of operations defined, it is time to download data. This should be as simple as selecting the "Download OSM Data" option in the Map menu. This will hit the java XAPI service hosted by MapQuest Open and download the data within your specified bounds. One problem with Maperitive is that its network timeout is very short. So if you get an error that says "The operation has timed out" then the XAPI server just responded too slowly. You can try again but you may need to reduce the size of your bounding box or try one of the other XAPI servers listed on the XAPI wiki page. To specify the server you add an "xapi-url=" argument to the command. I hit my own XAPI server that I have set up here at home. To do this I issued this command:
download-osm xapi-url=http://localhost:8080/xapi/api/0.6/*

Alternatively you can download the data using another method. (in JOSM or the "Export" tab on osm.org to name two)  Then you can go to the File menu and use the "Open Map Sources" option to load the file.

Once the data is loaded, turn off the Web map display by clicking the star over in the Map Sources tab. This will remove the tiles downloaded from osm.org from the display and show only what Maperitive has rendered from the downloaded data. It will be fairly similar but not identical.

Generating the tiles
Almost done! Now all you have to do is generate tiles. First, make sure that the web map layer is disabled or deleted in the Map Sources tab. Otherwise Maperitive uses map tiles from osm.org as a background layer. This causes it to scrape tiles which is what we are trying to avoid in the first place! There is a command in the Tools menu that will generate tiles. By default it uses how far you are zoomed in on the map window and renders 5 zoom levels of tiles based on that. If you want to generate a wider range of zoom levels, go back to the command line. This will render your bounding area from zoom level 8 down to 18:
generate-tiles minzoom=8 maxzoom=18

The tiles will be generated in a directory named "Tiles" inside of the Maperitive directory, wherever you unzipped it to. If you are going all the way to zoom level 17 and 18, it could take a while to render so go outside and collect some map data or something.

When the process finishes, you will have a standard tile directory tree just like you would have had by scraping tiles from osm.org with Mobile Atlass Creator or whatever other scraping software people have come up with. Load it onto a phone for offline viewing or throw it up on a web server using OpenLayers... whatever your heart desires.

Easy updating
Maperitive supports making simple scripts. So if you intend on updating your tiles periodically you might want to make a script so you can just fire and forget. Scripts are run from the File menu. Here is one that performs all the steps listed above for my county but only renders tiles between level 8 and 15. It takes about 90 seconds to execute including download time from the XAPI which can vary depending on current server load and size of area. You can copy this script, change the numbers in the bounds-set command and the zoom levels you want to render and then run it to generate tiles for your desired area. Maperitive expects script files to have a .mscript extension.

clear-map
use-ruleset alias=default
bounds-set -96.964,39.025,-96.547,39.573
download-osm
generate-tiles minzoom=8 maxzoom=15

Maperitive can do a lot of other things like adding hillshading or relief contours (elevation information) to the map.There are also several styles that come with Maperitive besides the mapnik look-alike one. You can poke around the menus to see some of this functionality or execute the help-commands command on the command line to get a list of all available commands. More information about a specific command can be seen by using help-commands again and adding the specific command you want more information about. Example: help-commands generate-tiles will give you more details about the command that renders tiles.

I think I am going to do another post about Maperitive that will go in to more details about customizing rendering rules for a specific purpose. Until then, happy rendering!

8 comments:

  1. This is great, I'm just sorry I discovered it later. I had no problem rendering tiles and using scripts for updating. If you are not comfortable with command line, use the menu to set boundaries, download, generate tiles, etc. Thanks for the great info couldn't be easier.

    ReplyDelete
  2. Thanks. I managed to generate tiles from .osm file using this software. Really2x thanks for this tutorial

    ReplyDelete
  3. Great..
    I have generated the tiles now how i can utilize it on web mapping application.
    i knw its done through Open layer or Leaf let
    but do i need to install mod_tile ?

    Moreover i am setting up my own osm server so any help, tutorial or flow of this would be appreciated

    ReplyDelete
  4. Hi Toby,

    actually i tried to install maperitiv on Mac and therefor i installed XQuartz-2.7.7 (X11 i think) and Mono (i also run the test to check if the network is working) but when i try o start Maperitiv now i get this feedback in Terminal. Do you know what i did wrong?

    System.EntryPointNotFoundException: GdipCreateFromContext_macosx
    at (wrapper managed-to-native) System.Drawing.GDIPlus:GdipCreateFromContext_macosx (intptr,int,int,intptr&)
    at System.Drawing.Graphics.FromHwnd (IntPtr hwnd) [0x00000] in :0
    at System.Windows.Forms.XplatUICarbon.PaintEventStart (System.Windows.Forms.Message& msg, IntPtr handle, Boolean client) [0x00000] in :0
    at System.Windows.Forms.XplatUI.PaintEventStart (System.Windows.Forms.Message& msg, IntPtr handle, Boolean client) [0x00000] in :0
    at System.Windows.Forms.Control.WmPaint (System.Windows.Forms.Message& m) [0x00000] in :0
    at System.Windows.Forms.Control.WndProc (System.Windows.Forms.Message& m) [0x00000] in :0
    at System.Windows.Forms.ScrollableControl.WndProc (System.Windows.Forms.Message& m) [0x00000] in :0
    at System.Windows.Forms.ToolStrip.WndProc (System.Windows.Forms.Message& m) [0x00000] in :0
    at System.Windows.Forms.StatusStrip.WndProc (System.Windows.Forms.Message& m) [0x00000] in :0
    at System.Windows.Forms.Control+ControlWindowTarget.OnMessage (System.Windows.Forms.Message& m) [0x00000] in :0
    at System.Windows.Forms.Control+ControlNativeWindow.WndProc (System.Windows.Forms.Message& m) [0x00000] in :0
    at System.Windows.Forms.NativeWindow.WndProc (IntPtr hWnd, Msg msg, IntPtr wParam, IntPtr lParam) [0x00000] in :0
    System.EntryPointNotFoundException: GdipCreateFromContext_macosx
    at (wrapper managed-to-native) System.Drawing.GDIPlus:GdipCreateFromContext_macosx (intptr,int,int,intptr&)
    at System.Drawing.Graphics.FromHwnd (IntPtr hwnd) [0x00000] in :0
    at System.Windows.Forms.Control.CreateGraphics () [0x00000] in :0
    at System.Windows.Forms.TextBoxBase.CreateGraphicsInternal () [0x00000] in :0
    at (wrapper remoting-invoke-with-check) System.Windows.Forms.TextBoxBase:CreateGraphicsInternal ()
    at System.Windows.Forms.Document.owner_HandleCreated (System.Object sender, System.EventArgs e) [0x00000] in :0
    at System.Windows.Forms.Control.OnHandleCreated (System.EventArgs e) [0x00000] in :0
    at System.Windows.Forms.TextBoxBase.OnHandleCreated (System.EventArgs e) [0x00000] in :0
    at System.Windows.Forms.TextBox.OnHandleCreated (System.EventArgs e) [0x00000] in :0
    at System.Windows.Forms.Control.WmCreate (System.Windows.Forms.Message& m) [0x00000] in :0
    at System.Windows.Forms.Control.WndProc (System.Windows.Forms.Message& m) [0x00000] in :0
    at System.Windows.Forms.TextBoxBase.WndProc (System.Windows.Forms.Message& m) [0x00000] in :0
    at System.Windows.Forms.TextBox.WndProc (System.Windows.Forms.Message& m) [0x00000] in <filename


    ... and some more lines.

    ReplyDelete
  5. Thanks for this.. I was able to create a webpage using leaflet.js to render the map of a city while offline. Noticed the tiles.json created by Maperitive.. it has all the relevant bounding, min-max zoom, center, etc data in it. Presently I have to manually copy that into the HTML file. Wondering if you can help make it load them from the json itself? See here for detailed question : http://gis.stackexchange.com/questions/129618/html-map-page-needs-to-load-bounding-parameters-from-maperitives-tiles-json

    ReplyDelete
  6. What an awesome and very nice post. I just stumbled upon your weblog and wanted to say that I’ve really enjoyed browsing your blog posts.

    In any case I will be subscribing to your rss feed and I hope you write again very soon!



    pave tile - website

    ReplyDelete
  7. Interesting and amazing how your post is! It Is Useful and helpful for me That I like it very much, and I am looking forward to Hearing from your next..
    Ceramic flooring

    ReplyDelete
  8. I wanted to thank you for this great read!! I definitely enjoying every little bit of it I have you bookmarked to check out new stuff you post.
    marble floor tile

    ReplyDelete