I've been Slippy Tiles Wiki page for equations to convert lat/long values (given via the user) to tile references, and then work with the data relating to the tile.

My problem is the wiki's equation always does one of the following:

  • Returns a location 20+ miles away from my given lat/long. The range is ~18 miles to 200+ miles, no consistency.

  • Returns absolutely nothing, and the tile_row value (XXXXX) is always off by a considerable amount. This ranges from 40 (10810 instead of 10850) to 300+ (10417 in stead of 10817).

This happens for all lat longs, sourced from varying online mapping tools. So far I've tested this with Google Maps, OSM's own browsing tool and used lat/long generation tools for random locations across the UK.

Here's my code so far:

    public void UserQuery()
        Console.Write("Please enter a latitude value: ");
        double userLat = Convert.ToDouble(Console.ReadLine());
        Console.Write("Please enter a longitude value: ");
        double userLong = Convert.ToDouble(Console.ReadLine());

        _merc.TileLat =  Math.Floor((1.0 - Math.Log(Math.Tan(DegreesToRadians(userLat)) + 1.0 / Math.Cos(DegreesToRadians(userLat))) / Math.PI)  * (1 << ZoomLevel));
        _merc.TileLong = Math.Floor((userLong + 180.0) / 360.0 * (1 << ZoomLevel));

    private double DegreesToRadians(double angle)
        return Math.PI * angle / 180;

The longitude value works perfectly everytime, it's just in there for reference.

The wiki's version of the equation is:

((1.0 - Math.Log(Math.Tan(lat * Math.PI / 180.0) + 1.0 / Math.Cos(lat * Math.PI / 180.0)) / Math.PI) / 2.0 * (1 << zoom));

but my problem is that the last / 2 before bitshifting returns a value half of what's generally expected, so 5308 instead of 10616. In terms of changes made to the equation, that's the only difference. I created a small method to work out radians => degrees because the original was hard to read and track (problems with brackets).

1 Answer 1


Bit-shifting is not the same as raising to a power. (unless you happen to shift the number two).

  • The end result always remained the same if I used a bitshift or a Math.Pow on the same part of the equation. I had tested that out but it remained identical. Jul 6, 2016 at 10:39
  • Just tested out the same lat/long 52.298059, -2.018458 with the above code and Math.Pow(2, zoomLevel) and both returned the same tile_row 10779 which doesn't exist. Jul 6, 2016 at 10:42
  • I've found that the ... / pi()) / 2 always gave me half of the tile_row value. So 10926 would be returned as 5463, meaning I'd have to take out the / 2 to get a result even close to the provided data. Would you be able to send me a more extensive gist of your code so I could take a look and see where I'm going wrong? Jul 6, 2016 at 10:54
  • This is my (working) PHP-code, based on the equations there: function get_tile_x($lon, $zoom) { return floor((($lon + 180) / 360) * pow(2, $zoom)); } function get_tile_y($lat, $zoom) { return floor((1 - log(tan(deg2rad($lat)) + 1 / cos(deg2rad($lat))) / pi()) /2 * pow(2, $zoom)); } PS. Where does your zoomlevel come from?
    – peter
    Jul 6, 2016 at 11:00
  • What are you passing in for a $lat value in terms of format? I'm inputting something such as 52.298059 which is problematic, are you using the same or something different? Jul 6, 2016 at 11:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.