Skip to content

Instantly share code, notes, and snippets.

@gopi-ar
Last active April 2, 2018 04:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gopi-ar/7c44a47c2b0f920b34cf7641bd74733d to your computer and use it in GitHub Desktop.
Save gopi-ar/7c44a47c2b0f920b34cf7641bd74733d to your computer and use it in GitHub Desktop.
This script shows that we need to add round() before applying floor() in the Slippy Map Tiles' lat2tile() function. We also need to add (int) to avoid '-0' values. The bug is because PHP uses double-precision floating point numbers (https://stackoverflow.com/a/1863740/1094271)
<?php
/**
* This script shows that we need to add round() before applying floor() in the lat2tile() function. We also need to add (int) to avoid '-0' values.
* The bug is because PHP uses double-precision floating point numbers (https://stackoverflow.com/a/1863740/1094271)
*/
$tiles = [];
//Demonstrating only till z3, you can increase if you like
for ($zoomLevel = 0; $zoomLevel <= 3; $zoomLevel++) {
$tiles[$zoomLevel] = getTilesCount($zoomLevel);
}
print_r($tiles);
function lon2tile($lon, $zoom) {
return (floor(($lon + 180) / 360 * pow(2, $zoom)));
}
//Function originally from https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Lon..2Flat._to_tile_numbers_5
function lat2tileOriginal($lat, $zoom) {
return (floor((1 - log(tan($lat * M_PI / 180) + 1 / cos($lat * M_PI / 180)) / M_PI) / 2 * pow(2, $zoom)));
}
//Fixing this by rounding before floor, and casting as (int)
function lat2tileFixed($lat, $zoom) {
return (int)(floor(round((1 - log(tan($lat * M_PI / 180) + 1 / cos($lat * M_PI / 180)) / M_PI) / 2 * pow(2, $zoom),1)));
}
/**
* Get number of tiles for whole map
* @param int $zoom
* @return int number of tiles
*/
function numTiles($zoom)
{
return pow(2, $zoom);
}
/**
* Get longitude from tile x value
*
* @param int $x
* @param int $zoom
* @return float longitude
*/
function tileToLon($x, $zoom)
{
return $x / numTiles($zoom) * 360.0 - 180.0;
}
/**
* Get latitude from tile x value
*
* @param int $y
* @param int $zoom
* @return float latitude
*/
function tileToLat($y, $zoom)
{
$n = pi() * (1 - 2 * $y / numTiles($zoom));
return rad2deg(atan(sinh($n)));
}
function getTilesCount($zoom) {
global $landOnlyKV;
$top_tile = 0;
$left_tile = 0;
$bottom_tile = numTiles($zoom)-1;
$right_tile = numTiles($zoom);
//tile count by z level
$tilesCount = 0;
for ($x = $left_tile; $x < $right_tile; $x++) {
for ($y = $top_tile; $y <= $bottom_tile; $y++){
$tilesCount++;
//original Tile ID
$v1 = "$zoom/$x/$y";
//buggy conversion
//convert to lat/lon
$lon = tileToLon($x, $zoom);
$lat = tileToLat($y, $zoom);
//convert back to tile at z7
$newX = lon2tile($lon, $zoom);
$newY = lat2tileOriginal($lat, $zoom);
$v2 = "$zoom/$newX/$newY";
//patched conversion
$lon = tileToLon($x, $zoom);
$lat = tileToLat($y, $zoom);
//convert back to tile at z7
$newX = lon2tile($lon, $zoom);
$newY = lat2tileFixed($lat, $zoom);
$v3 = "$zoom/$newX/$newY";
if($v1 != $v2 || $v1 != $v3) {
echo "{$v1},{$v2},{$v3}\n";
}
}
}
return $tilesCount;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment