Slippy map tilenames

From OpenStreetMap

Jump to: navigation, search

This article describes the file naming conventions for the Slippy Map application.

Contents

Zoom levels

0 1 tile covers whole world
1 2 × 2 tiles
2 4 × 4 tiles
n 2n × 2n tiles
17 Maximum zoom for Osmarender layer
18 Maximum zoom for Mapnik layer

X and Y

  • X goes from 0 (left edge is 180 °W) to 2zoom -1 (right edge is 180 °E)
  • Y goes from 0 (top edge is 85.0511 °N) to 2zoom -1 (bottom edge is 85.0511 °S) in a Mercator projection

For the curious, the num 85.0511 is the result of arctan(sinh(π)). By using this bound, the entire map becomes a (very large) square. See also the Osmarender bug.

Projection

  • Project the world as Mercator.
  • Divide the equator into n equal units -- those are the x values
  • Locate ±85.0511° on your projection -- those are the limits of the map in the Y axis
  • Divide the map's Y axis into n equal units -- those are the y values starting from 0 at the top

For those who like pseudo-code, here's some hints:

xtile = (lon+180)/360
ytile = log(tan(lat) + sec(lat))

For perl a subroutine could be:

use Math::Trig;
sub getTileNumber {
 my ($lat,$lon,$z) = @_;
 my $xtile = int( ($lon+180)/360 *2**$z ) ;
 my $ytile = int( (1 - log(tan($lat*pi/180) + sec($lat*pi/180))/pi)/2 *2**$z ) ;
 return(($xtile, $ytile));
}

In Actionscript 1:

function long2tile(lon) { return (Math.floor((lon+180)/360*Math.pow(2,_root.scale))); }
function lat2tile(lat)  { return (Math.floor((1-Math.log(Math.tan(lat*Math.PI/180) + 1/Math.cos(lat*Math.PI/180))/Math.PI)/2 *Math.pow(2,_root.scale))); }

For Java that is:

public class slippytest {
public static void main(String[] args) {
  int zoom = 10;
  double lat = 47.968056d;
  double lon = 7.909167d;
  System.out.println("http://tile.openstreetmap.org/" + getTileNumber(lat, lon, zoom) + ".png");
}
public static String getTileNumber(final double lat, final double lon, final int zoom) {
  int xtile = (int)Math.floor( (lon + 180) / 360 * (1<<zoom) ) ;
  int ytile = (int)Math.floor( (1 - Math.log(Math.tan(lat * Math.PI / 180) + 1 / Math.cos(lat * Math.PI / 180)) / Math.PI) / 2 * (1<<zoom) ) ;
   return("" + zoom + "/" + xtile + "/" + ytile);
  }
}

For VB.NET a subroutine could be:

Private Function CalcTileXY(ByVal lat As Single, ByVal lon As Single, ByVal zoom As Long) As Point
   CalcTileXY.X  = CLng(Math.Floor((lon + 180) / 360 * 2 ^ zoom))
   CalcTileXY.Y = CLng(Math.Floor((1 - Math.Log(Math.Tan(lat * Math.PI / 180) + 1 / Math.Cos(lat * Math.PI / 180)) / Math.PI) / 2 * 2 ^ zoom))
End Function

A python implementation


And the other direction in perl:

 sub Project {
  my ($X,$Y, $Zoom) = @_;
  my $Unit = 1 / (2 ** $Zoom);
  my $relY1 = $Y * $Unit;
  my $relY2 = $relY1 + $Unit;

  # note: $LimitY = ProjectF(degrees(atan(sinh(pi)))) = log(sinh(pi)+cosh(pi)) = pi
  # note: degrees(atan(sinh(pi))) = 85.051128..
  #my $LimitY = ProjectF(85.0511);

  # so stay simple and more accurate
  my $LimitY = pi;
  my $RangeY = 2 * $LimitY;
  $relY1 = $LimitY - $RangeY * $relY1;
  $relY2 = $LimitY - $RangeY * $relY2;
  my $Lat1 = ProjectMercToLat($relY1);
  my $Lat2 = ProjectMercToLat($relY2);
  $Unit = 360 / (2 ** $Zoom);
  my $Long1 = -180 + $X * $Unit;
  return(($Lat2, $Long1, $Lat1, $Long1 + $Unit)); # S,W,N,E
 }
 sub ProjectMercToLat($){
  my $MercY = shift();
  return( 180/pi* atan(sinh($MercY)));
 }
 sub ProjectF
 {
  my $Lat = shift;
  $Lat = deg2rad($Lat);
  my $Y = log(tan($Lat) + (1/cos($Lat)));
  return($Y);
 }

The other way in Actionscript 1:

function tile2long(t) {
 return (t/Math.pow(2,_root.scale)*360-180);
}
function tile2lat(t) {
 var n=Math.PI-2*Math.PI*t/Math.pow(2,_root.scale);
 return (180/Math.PI*Math.atan(0.5*(Math.exp(n)-Math.exp(-n))));
}

Tiles

  • Tiles are 256 × 256 pixel PNG files
  • Each zoom level is a directory, each column is a subdirectory, and each tile in that column is a file
  • Filename(url) format is /zoom/x/y.png

The slippy map expects tiles to be served up at URLs following this scheme, so all tile server URLs look pretty similar. For example:

Mapnik tiles from the 'tile' server: http://tile.openstreetmap.org/8/127/85.png
Osmarender/Tiles@Home on the 'dev' server: http://tah.openstreetmap.org/Tiles/tile.php/8/127/85.png
Maplint tiles: http://tah.openstreetmap.org/Tiles/maplint.php/8/127/85.png
User:Firefishy's proxy: http://osm-tah-cache.firefishy.com/~ojw/Tiles/tile.php/8/127/85.png

Subtiles

If you're looking at tile x,y and want to zoom in, the subtiles are (in the next zoom-level's coordinate system):

2x, 2y 2x + 1, 2y
2x, 2y + 1 2x + 1, 2y + 1

Similarly, zoom out by halving x and y (in the previous zoom level)

Tools

References

Personal tools
recent changes