Local projections in a world of spherical mercator

Update 2014-02-24: A more thorough and updated version on the topic is The Hitchhiker’s Guide to Tiled Maps.

The premise: you want to use the new and cool open source mapping solutions like Leaflet, TileStache and TileMill. While you love projects like OpenStreetMap, you are in a position where you cannot throw out your old map tiles, that are rendered in some local projection, instead of the the one projection to rule them all, spherical mercator. You need to coerce these tools to use your projection and your tiles.

Fortunately, these tools do support local projections, or at least were designed with this support in mind. Yay! Less fortunately, it seems very few actually use that functionality, and if they do, they are not bloggers, since we at Kartena couldn’t find any useful information on how to go about configuring local projections. That’s why we’re here! We want to share the wonderful world of local projections with you.

What are projections?

A projection (in cartography) is a way of transforming a location on the earth, typically described by a latitude and longitude, to a flat surface (a map) coordinate, like x and y. Projections come in a myriad and shapes and flavors, and different projections have different advantages and disadvantages (you can read up on that on Wikipedia, for example).

What is tiling?

Tiling means that we chop up a large (sometimes really, truly, huge) bitmap into smaller more manageable bitmaps that can later be put together to appear as one seamless image again. Tiling is used since it would not be possible to render those huge bitmaps (too large to keep in memory), and because time to transfer the bitmap to a client would be  unacceptable. Also, the client rarely looks at the entire map area, and only need small parts of it.

A contract for tiling

To make tiling possible, we need to set a standard for how to reference a certain part of the larger bitmap – if the client needs to show a certain geographic area, it needs to know:

  1. Tile size and scales: how many tiles fit into that area
  2. Tile origin: what the (projected) coordinates of those tiles’ corners are
  3. Grid alignment: given the tile grid origin, in what directions do the row and column coordinates of the grid grow?
  4. Tile naming: how to request a tile from the server, given its row and column coordinate in the grid

These four points constitute a contract about how tiling is done, and server and client need to agree on this.

For the spherical Mercator projection, Google Maps has set up what has ended being a de facto standard for tiling in this projection. This standard makes it easy to use spherical mercator with many different combinations of map clients and tile servers, since the contract is well defined, well documented and implemented almost everywhere (some variations exist, more on that later).

For other projections, this represents more of a challenge: all of the points above can be specified in a number of ways. We need to break down the points to something we can express in code.

Tile size and scales

We first have to agree on how large each tile is, both in pixels and in projected coordinates.

Deciding the tile size in pixels is fairly easy. Google Maps uses 256×256 pixels, and if you don’t have any particular reason to do otherwise, so should probably you.

The size of a tile in projected coordinates is somewhat trickier. Another way of formulating this is: what zoom/scale levels do you need. Each level will result in a different tile size in projected coordinates.

For example, let’s say that you have a level with the scale of one pixel per 100 projected coordinates (scale 1:100). If your tile size, in pixels, is 256×256, the tile size in projected coordinates will be 256 / (1/100) = 256×100 = 25 600 projected coordinate units.

The other way around, you can take projected coordinate units and multiply them by scale to get pixels: 25 600 projected coordinate units = 25 600x(1/100) = 256 pixels.

To sum up, we need to specify these two things:

  • The tile size in pixels
  • The scale for each zoom/scale level.

Tile origin

Tiles are organized in a grid. The rows and columns of the grid are numbered, and to make this numbering unambiguous, we need to define where in the projected coordinate space the grids origin (0,0) is.

Each projection transforms a certain area of the earth into a certain coordinate space. This coordinate space varies for each projection. Take for example EPSG:2400 (Swedish coordinate system RT90). It is well defined for latitudes 55.2 to 69.1 degrees north, and longitudes 10.57 to 24.18 degrees east. This is projected to the x-coordinates 1166653.6161 to 2032341.6763 and y-coordinates 6131388.6471 to 7690505.5552. In this case, it might be suitable to choose an origin at top left (1166653.6161, 7690505.5552) or bottom left (1166653.6161, 6131388.6471). Or you might even define the origin as (0,0), or any other coordinate that suits you. The important thing is that client and server agrees on the origin, or they will actually use two different grids.

Grid alignment

To further define the grid, we need to decide how rows and columns in the grid are numbered. We know the coordinate of the origin of (0,0), but what does it mean, in terms of projected coordinates, to increment the row or column coordinate?

In the world of spherical Mercator, there are to approaches here:

  • Google Maps and OpenStreetMap set the grid’s origin at the top left and row coordinate grows downward, such that the row coordinate grows the further south you go. Columns grow from west to east (left to right).
  • TMS (Tile Map Service) set the origin at bottom left, such that the row coordinate grows the further north you go. Columns grow from west to east (left to right), like Google Maps.

Tile naming

Given the definitions above, we can unambiguously calculate the grid row and column for a projected coordinate. What remains is how to request this tile from the server. This basically boils down to deciding on a naming standard for the tiles.

One of the most popular, employed by both Google Maps/OSM and TMS is often summarized as xyz. This standard calls the row y, the column x and the zoom level z, where zoom levels are numbered from 0 (most zoomed out, largest scale) and more zoomed in with increasing numbers. An example of a tile can look like this:

http://mytileserver.com/sweden/3/127/32.png

A great number of naming strategies exist, instead of using the rows and columns, the projected coordinate of one of the tile’s corners can for example be used. Zoom level can be denoted by the actual scale used, or resolution (that is, effectively the inverse of the scale).

Getting down to details

This is all fine and well, but also very theoretical. How do we actually implement this, if we want to use our own definition instead of spherical Mercator?

A widely used and pretty flexible way to break this problem down is to use these four components:

  • Projection - projects latitude and longitude to x/y
  • Scale definitions - defines what zoom levels are available and the scale for each level
  • Coordinate to grid transformation matrix - describes how a projected coordinate is transformed to a row and column in the grid
  • Tile naming template - given zoom level, row and column forms the filename, URL, et c. for the tile

Projection

Projection can be done in a lot of ways. One of the most flexible is to use an implementation of Proj.4 for the language you’re working in. At Kartena, we use Proj4Js in Javascript and pyproj for Python. spatialreference.org has Proj.4 definitions for all frequently used coordinate reference systems.

Scale definitions

Depending on your requirements, this can either be a list of your zoom levels’ scales, or a function, if zoom levels follow such a pattern.

Coordinate to grid transformation matrix

Getting projected coordinates to grid coordinates involves first applying the grid origin and the grid alignment, and then the scale to convert the projected coordinate to pixel coordinates.

These are all so called linear transformations, which can be expressed by these formulas:

grid_col = int(scale * (a * proj_x + b))
grid_row = int(scale * (c * proj_y + d))

where scale is the current scale level and a, b, c and d are constants; these constants can be expressed as a transformation matrix.

For spherical Mercator, this matrix looks like this: (0.5 / π, 0.5, -0.5 / π, 0.5). This can be interpreted as the origin is at (b,d) = (0.5, 0.5). Both x and y axis is scaled by a factor of 0.5 / π, but the y axis is inverted (grows from north to south) since c has a negative sign.

At first, this transformation might be the hardest one to grasp (especially if you’re not a fan of math). To make it easier, here are two variants of the transformation matrix that generally works well for many local projections.

Local projection with google maps/OSM tiling scheme

For a local projection where you want to use the Google Maps/OpenStreetMap tiling scheme, where rows grow from north to south (and your projected coordinates go the other way, so that y grows further north), you want to do this:

  • Set origo at the top left of the covered area (the point furthest north and west). Call this (origo_x, origo_y)
  • The transformation matrix is: (1, origo_x, -1, origo_y)

LOCAL PROJECTION WITH TMS TILING SCHEME

For a local projection where you want to use the TMS tiling scheme, where rows grow from south to north (and your projected coordinates go the same way, so that y grows further north), you want to do this:

  • Set origo at the bottom left of the covered area (the point furthest south and west). Call this (origo_xorigo_y)
  • The transformation matrix is: (1, origo_x, 1, -origo_y)

Tile Naming Template

This is usually one of the easiest steps, usually just a set of string replacements.

Practical example

Wow, you’ve almost reached the end! Let’s take a quick look how this might look in practice.

At Kartena, our favourite map client is currently Leaflet. Our only real problem with it, was that out of the box it doesn’t support any local projections. To solve this, we have written a small project called Proj4Leaflet, that acts as glue between Leaflet and Proj4Js. With this project, and the information above, you can easily have tiling maps with any projection supported by Proj.4.

Using what we’ve talked about above, we can put this all together in a few lines of code:

var resolutions = [8192, 4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 0.5]
,crs = L.CRS.proj4js('EPSG:2400'
    ,'+lon_0=15.808277777799999 +lat_0=0.0 +k=1.0 +x_0=1500000.0 +y_0=0.0 +proj=tmerc +ellps=bessel +units=m +towgs84=414.1,41.3,603.1,-0.855,2.141,-7.023,0 +no_defs'
    ,new L.Transformation(1, 0, -1, 0))
    ,scale: function(zoom) {
      return 1 / resolutions[zoom];
    }
    [...]
})
,mapUrl = 'http://api.geosition.com/tile/lmv/{z}/{x}/{y}.png'

First, we define the resolutions that we are going to use for the different zoom levels. Note that resolution (meters/pixel) is the inverse of scale (pixels/meter). This is reflected by the use of our custom scale function, which returns the inverted value.

We then set up the CRS (Coordinate Reference System) with its name, “EPSG:2400″, and the Proj.4 definition (the really long string).

Next, we set up the transformation matrix, exactly as described above. In this case, we have put origo at (0,0) and use the Google Maps/OSM tiling scheme, with rows growing from north to south. (Note that this results in row coordinates being negative; this is something we use for the “cleanness” of using a simple origo as (0,0)).

The last line is the string template for getting the actual tile URL, following the xyz scheme mentioned above.

86 thoughts on “Local projections in a world of spherical mercator

  1. Hello,
    Very very nice post, detailed. I wish i had a resource like that when i started using tms services (wikipedia is a bit light on the subject).
    I am actually part of the ones who use your leaflet extension, proj4leaflet to overlay some french data in french projections, but not mixed with OSM, i just overlay services with the same proj. I actually tried mixing tms services with different projections but it seems that it can’t be done, even with only one visible tms at a time. Leaflet has a global CRS prop and calculate the pixel origins once and because local and global dont have the same origin, it can never work.
    Anyway, i didnt blog about it because most users will use OSM and don’t have custom TMS, especially some with the Y dimension inverted (tricky one).

    Great work!
    Fabien

    • Hi Fabian, do you have a copy of your code I could look at I am trying to do something similar with INSPIRE WMS projected in to ETRS:27700 Thanks Andrew

  2. Hello!

    Thanks for very useful arcticle.
    Can you please clarify why you used custom scale function
    function(zoom) { return 1 / resolutions[zoom];
    and do not use Leaflet’s native one:
    function (zoom) { return 256 * Math.pow(2, zoom); }

    Thanks.

  3. Excellent post ! I could clarify a lot of things in my mind with your explanations !

    One thing about transformation matrices, I don’t really catch why I had to use this this transformation matrix when using the Lambert93 (2154) projection (tms==true):

    (1, -SouthWest.lng, -1, SouthWest.lat)

    (notice the negative sign on origo_x and positive on origo_y)

    Thank you again :)

  4. Pingback: » Leaflet and Vicgrid (EPSG:3111) projection nyalldawson.net

  5. I have a question regarding usage of leaflet. Is it possible to have tile 0,0 in the centre of the map and have it spread out in all directions from there; as you go left tiles have an decreasing negative number (-1, -2. -3, …) and as you go right tiles have an increasing positive number. Similarly with up and down.
    My reason is that in my usage of leaflet the map can keep growing in any direction, it doesn’t have a fixed size.
    Many thanks in advance

  6. Pingback: Geospatial API’s and other tools for developers | Go-Geo! blog

  7. Thank you for the explanation post.
    However I’m still struggling how to setup the proj4Leaflet library.

    In the example html you link to several js files. I am guessing that the script.js is the one where you setup the projection, everything you talk about in this post and the Leaflet map layer. But what does the (http://www.mapuse.com/billing/Client/v1/Leaflet.js) do?

    Thx for the reply in advance.

  8. Pingback: Using TileMill Without Spherical Mercator | Kartena Developer Blog

  9. It’s a pity you don’t have a donate button! I’d most certainly donate to this superb blog! I guess for now i’ll
    settle for book-marking and adding your RSS feed
    to my Google account. I look forward to new updates and will share this site with my Facebook
    group. Chat soon!

  10. The beauty of using oils in barbecue marinades is that they are readily available off the shelf with a variety of flavors already locked in.
    Puree the olives, butter, and garlic together until smooth.
    The easiest way to fix sliced liver is simply to fry it in
    an open skillet using just a tad of butter, margarine or
    oil.

  11. Very great post. I just stumbled upon your blog and wanted to mention
    that I’ve truly loved browsing your weblog posts. After all I will be subscribing for your rss feed and I hope you write once more very soon!

  12. Excellent beat ! I wish to apprentice while you amend your site, how could i subscribe
    for a blog website? The account aided me a acceptable deal.

    I had been a little bit acquainted of this your broadcast offered bright clear idea

  13. Attractive section of content. I just stumbled upon your site and in accession capital to assert that I get
    actually enjoyed account your blog posts. Anyway I’ll be subscribing to your augment and even I achievement you access
    consistently fast.

  14. I’ve been browsing online greater than three hours
    lately, but I by no means found any interesting article
    like yours. It is beautiful worth sufficient for me.

    In my opinion, if all webmasters and bloggers made excellent content as you probably did, the internet might
    be much more useful than ever before.

  15. Pingback: Free Online Article Spinner Download

  16. I have figured out some significant things through your site post. One other subject I would like to state is that there are plenty of games on the market designed specially for preschool age young children. They contain pattern recognition, colors, pets, and models. These generally focus on familiarization in lieu of memorization. This will keep little ones engaged without feeling like they are learning. Thanks

  17. Howdy! Quick question that’s totally off topic. Do you know how to make your site mobile friendly? My website looks weird when browsing from my iphone. I’m trying to find a theme or plugin that might be able to resolve this problem. If you have any recommendations, please share. Appreciate it!

  18. Hiya! Quick question that’s completely off topic. Do you know how to make
    your site mobile friendly? My website looks weird when viewing
    from my iphone. I’m trying to find a theme
    or plugin that might be able to correct this problem.
    If you have any suggestions, please share. Appreciate it!

    Also visit my weblog … web page

  19. I do believe all of the concepts you have offered in your post.
    They’re really convincing and will definitely work.
    Still, the posts are very quick for novices. Could you please extend them a little from next time?
    Thank you for the post.

    Look at my site: homepage

  20. Hello! This is my first visit to your blog! We are a group of volunteers
    and starting a new initiative in a community in the
    same niche. Your blog provided us beneficial information to
    work on. You have done a extraordinary job!

    Check out my web site; web page

  21. Somebody essentially assist to make significantly posts I’d state.
    That is the first time I frequented your web page and up to now?
    I surprised with the analysis you made to create this particular
    post extraordinary. Wonderful process!

    Here is my webpage – homepage

  22. I just couldn’t leave your website before suggesting that I actually enjoyed the standard info a
    person provide on your visitors? Is gonna be back frequently in order to
    investigate cross-check new posts

  23. Hey! Quick question that’s totally off topic. Do you
    know how to make your site (Lynette) mobile
    friendly? My blog looks weird when browsing from my iphone 4.
    I’m trying to find a template or plugin that might be able to fix this issue.

    If you have any suggestions, please share. Appreciate it!

  24. Pingback: Noticias 14-01-2014 - La Web de Programación

  25. I believe that avoiding highly processed foods may be the first step to help lose weight. They could taste excellent, but refined foods have very little vitamins and minerals, making you consume more just to have enough vigor to get with the day. When you are constantly eating these foods, moving over to cereals and other complex carbohydrates will help you to have more power while feeding on less. Good blog post.

  26. Hello there, just became aware of your blog thru Google, and found that it’s truly informative. I am gonna be careful for brussels. I will appreciate if you happen to proceed this in future. Lots of folks shall be benefited from your writing. Cheers!

  27. Rien ne pouvait opleve tenir with leurs moyens lorsqu’ils découvrent qu’ils souhaitent acquérir à n’t seule decided upon. Celui-ci n’a marche l’attention the ce qui concerne l’argent. Del in addition personnes ayant fait pueden démarquer certains autres, l’ensemble l’ordre nufactured ces chaussures seront généralement très co?teux .

  28. Undeniably believe that which you said. Your favorite reason appeared to be on the web the easiest thing to be aware of. I say to you, I certainly get irked while people think about worries that they plainly don’t know about. You managed to hit the nail upon the top and defined out the whole thing without having side-effects , people could take a signal. Will probably be back to get more. Thanks

  29. For the past a couple of many years, Hurd has been a wildlife rescuer in the Wildlife Training and Rehabilitation Center or Wildlife Inc. exactly where he operates to 1st capture then rehabilitate a host of species, assisting them recover from their injuries or illnesses ahead of returning them for the wild.
    Cheap Black Nobis The Kato Men’s Peacoat http://www.possupedia.net/cheap-black-nobis-the-kato-mens-peacoat-p-2.html

  30. Completely cool token of mail! You have a power for chirography and I’m really amazed at how trickle you stock with the laying of captivating content. If I was as competent as you, I’d be journalism leading article unless the newspaper! This clearly you’re born, you can not develop the unaltered genre as good day-to-day, at least my be sure, and dialect mayhap I’m not a writer, but fiction is something I know. Retirement community curious, as I mentioned earlier and the corresponding my tastes and interests. You be required to a postal card on and broaden in this because the wreck to let pass such a burly knack, what you deceive been blessed with. You devise take it on the lam epoch to a acquaintance, maybe this name will contain more traffic, I trust so because what you write should be directed to one in an serene modus vivendi = ‘lifestyle’ and embolden the reading relaxed and approachable reading, written with advantage flavor and taste.

  31. I just want to share it with you that I’m really fresh to wordpress blogging and extremely cherished your write-up. Quite possibly I am probably to store your web post . You really have excellent article text. Admire it for swapping with us your internet site document.

  32. First of all I would like to say wonderful blog!
    I had a quick question that I’d like to ask if you do not
    mind. I was interested to know how you center yourself and
    clear your thoughts before writing. I have had a hard time clearing my
    mind in getting my ideas out there. I truly do take pleasure in
    writing but it just seems like the first 10
    to 15 minutes tend to be lost simply just trying to figure out how
    to begin. Any suggestions or hints? Cheers!

    my blog post real racing 3 hack

  33. In southeastern Pennsylvania, an 84 year old man was killed when a snow laden tree fell on his home while he was napping in his recliner.In Massachusetts, a 20 year old man died in Springfield after being electrocuted by a power line downed by high winds and wet, heavy snow.

  34. 4. Mai 01.38 Amyes, wird es Rückschläge sowohl in Silber, Gold, Platinmetalle sein. Überhaupt nicht eine Blase in Metallen. Warte nur 4 Tage wie auch 3 Dinge werden zu normalen mit Silber wie auch Gold weiter wieder nach oben zurück. Und falls Sie Selbst etwas neues Geld, jetzt zu investieren, dann haben Sie Selbst die Möglichkeit, zu verkaufen, die Dollar wie auch kaufen einige Metall-oder Bergleute billig.Holen Sie sich Entspannung

  35. Die Ausbildung von Polizei und ebenfalls andere bewaffnete Profis durch ist ein Job für sich. Sie haben zu trainieren, um eine Situation zu erkennen, zu wissen, ob sie wirklich brauchen, um zu schießen und ebenfalls nicht aus emotionalen Schock reagieren, brauchen sie ständige Praxis zu gewährleisten, daß sie eine richtige Ziel und ebenfalls nicht ein Zuschauer zu schlagen, eine sie benötigen, körperliches Training, um eine Waffe in behalten ihre Kontrolle sollten sie sprang erhalten (in dieser Regel haben sie auch Backup-als auch)

  36. I was suggested this blog by my cousin. I’m not sure whether this post is written by him as no one else know such detailed about my difficulty. You are wonderful! Thanks! bekakfggefkd

  37. If you are a team of experts, including Alastair Welch,
    to help foreigners looking to take advantage of both the M25 and pick up some cash at your departure terminal.

    If a business passenger exits the secure boarding area for any
    reason. Continue along the M23 until junction 9 and exit onto
    the Southern Perimeter Road. The cost for parking here is much of
    a surprise to me. Today, while the plane,
    I found I was sitting next to two young Israeli men. Either way, the news regarding a negative business encounter will spread very fast.

    Here is my webpage business car insurance

  38. Hi there, I discovered your site by means of Google while searching
    for a comparable subject, your web site came up, it appears great.
    I’ve bookmarked it in my google bookmarks.
    Hi there, simply changed into alert to your blog
    thru Google, and found that it is truly informative.
    I’m gonna be careful for brussels. I’ll appreciate in case you proceed
    this in future. Lots of people can be benefited from your writing.
    Cheers!

    Look at my blog post Malarone

  39. I got this web page from my buddy who told me about this web site
    and now this time I am browsing this website and reading very informative articles at this place.

  40. Although maximum site owners are familiar
    with these concepts, but they may lack the expertise to do it the correctly.
    As the culture of internet slang grew, it took on new origins from pop culture
    or video games and television. A internet marketing business, in a
    nutshell, a business that’s designed to run on the internet via
    a website.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">