Download open street map tiles for offline usage

3 minute read | October 15, 2017

Hi everyone! Today I want to talk about downloading open street map tiles for offline usage. I’ll tell you about my journeys with them and give some links. Let’s get started.

Why did I need them?

One of my clients wanted to have a mobile app with offline maps. I was writing API for it. Packing all arrays and adding maps to them were required because I needed to calculate final sizes of the arrays.

How offline maps works?

Let’s think about earth’s map like about table. We have rows and columns. So, every piece of the land can be represented with the cell in this table. You can ask me - “But how zooms works? How can I zoom-in and zoom-out maps in applications. If we have only one table?” - My answer - we have different tables. Each one for the level of zoom. For example in our application we used 12-15 levels.

I can’t say about another map’s systems, but open street map has 19 levels of zoom. For example, level 0 represents the whole world and level 13 represents a village or town.

You need at least 2 or 3 zoom levels for getting application’s map works well (correct zoom, small viewing issues, users’ satisfaction :) )

Where can I grab them?

First of all, you need to understand that OSM is OSS. So, when you dowload data from their services, you will have to think about the consequences for all community. Official policy tells you more about rules and don’ts.

This page contains some useful info about tiles, such as list of servers, tools and so on. As for me I was using official server with 3 subdomains:

Implementation

First of all you need coordinates of the area. I higly recommend this tool.

Let’s imagine we need map of Saint-Petersburg for offile using. There a few steps, which we need to do for getting them:

1. Getting coordinates

  • Go to CD tab and notice Osmosis Copy field

You need coordinates of two points. Bottom left and top right. You need them because of tiles presenting system. As I said in the first paragraph, tiles are stored in the grid (table) format. For calculating numbers of tiles, we need to know coordinates of the left bottom tile (number 1 on the picture) and top right tile. If we know them, we are able to calculate ranges.

2. Writing code

  • Go to the github and see this package. It contains the great example of tiles abstraction writing with C# language.

  • Create two tiles with coordinates, which you got in getting coordinates section.

   var leftBottom = Tile.CreateAroundLocation(double.Parse("59.17"), double.Parse("28.63"), 14);
   var topRight = Tile.CreateAroundLocation(double.Parse("60.85"), double.Parse("31.81"), 14);
  • Then create TileRange and be ready for dowloading tiles :)
  //dirty, but obvious :)
  var minX = Math.Min(leftBottom.X, topRight.X);
  var maxX = Math.Max(leftBottom.X, topRight.X);

  var minY = Math.Min(leftBottom.Y, topRight.Y);
  var maxY = Math.Max(leftBottom.Y, topRight.Y);

  var tiles = new TileRange(minX, minY, maxX, maxY, zoom);

3. Downloading tiles

Fow downloading tiles. You need to do GET requests in {server}.tile.openstreetmap.org/{zoom}/{x}/{y}.png format. Where:

  • {server} - symbol of server (a,b,c)
  • {zoom} - level of zoom
  • {x} - x position of the tile
  • {y} - y postion of the tile
    foreach(var tile in tiles){
      //only one server name is just for the example. It's not recommended to use only 1 server endpoint
      var endpointUrl = $"http://a.tile.openstreetmap.org/14/{tile.X}/{tile.Y}.png"
    }

4. Example of downloading tiles

Example below is just my personal implementation and I don’t force you to do it in the same way

        private readonly string[] _serverEndpoints = {"a", "b", "c"};

        public async Task DownloadTiles(int cityId, TileRange range, int zoom)
        {
            var random = new Random();
            var maxDegreeOfParalellism = 2;
            await range.ParallelForEachAsync(async tile =>
            {
                var url =
                    $"http://{_serverEndpoints[random.Next(0, 2)]}.tile.openstreetmap.org/{zoom}/{tile.X}/{tile.Y}.png";
                var data = await _client.GetByteArrayAsync(url);

            }, maxDegreeOfParalellism);
        }

ParallelForEachAsync available on github.

maxDegreeOfParalellism equals two because of official policy.

P.S.

I need to say again, that OSM is OSS project. This means that you shouldn’t build software with massive calls to OSM endpoints. If you do this, your IP will be ban. If you need to serve a lot of client requests, you can create your own tiles server or use paid-solutions.

Conclusion

That’s all. I’ll be happy, It this article helps you.

Leave a Comment