I am trying to generate map tiles based on data we have stored in a DB and serve them up to Cesium using an UrlTemplateImageryProvider. For each map tile, I need to know the lat/long bounds in order to find matching data. I'm using the same tile scheme as Google Maps with a request like http://host/tiles/zoom/x/y. Initially I've been using the equations to convert these map tile coordinates into lat/long bounds found here: http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Tile_bounding_box but now I'm wondering if this is not the correct projection to be using.
For starters, all the Web Mercator documentation I see says that Tile 0,0 @ zoom lvl 0 should cover the entire world. That's not what I see with Cesium (there are 2 tiles at zoom level 0). That said, my calculations seem to work for zoom levels 0, 1, 2, and 3, but as I go to zoom level 4, the Latitude calculation starts to move south. If I plot my generated lat, long points on a 2D Google Map, they look correct, but I can clearly see that the tiles requested by cesium have different bounds. So I am now assuming I'm just using the wrong projection to calculate the tile bounds.
I've also tried the calculations here: http://www.maptiler.org/google-maps-coordinates-tile-bounds-projection/ converting from pixels, to meters, to lat/long but they seem to be the same results as the web mercator calculations.
So can anyone help me figure out how to calculate a Lat/Long bounding box for the tiles requested by Cesium?
Here are the methods I have based on the Slippy Map Tiles:
public static Box getLatLonBoundsForTile(int zoom, int x, int y) {
double longitudeMin = tile2lon(x, zoom);
double longitudeMax = tile2lon(x + 1, zoom);
double latitudeMin = tile2lat(y + 1, zoom);
double latitudeMax = tile2lat(y, zoom);
Point swPoint = new Point(longitudeMin, latitudeMin);
Point nePoint = new Point(longitudeMax, latitudeMax);
return new Box(swPoint, nePoint);
}
public static double getColsForZoomLevel(int zoom) {
if (zoom == 0) return 2;
int noTiles = 8 * (int) (Math.pow(4, zoom - 1));
return noTiles / getRowsForZoomLevel(zoom);
}
public static double getRowsForZoomLevel(int zoom) {
if (zoom == 0) return 1;
return Math.pow(2, zoom);
}
public static double tile2lon(int x, int zoom) {
return x / getColsForZoomLevel(zoom) * 360.0 - 180;
}
public static double tile2lat(int y, int zoom) {
double n = Math.PI - (2.0 * Math.PI * y) / getRowsForZoomLevel(zoom);
return Math.toDegrees(Math.atan(Math.sinh(n)));
}