Mar-21-2024, 03:29 PM
Hi,
I'm something of a novice Python programmer so please bear with me. OpenStreetMaps uses a 'shortlink' protocol to create file names from lat/long coordinates, which is described here: https://wiki.openstreetmap.org/wiki/Shortlink. They also include links to various coding implementations; however, the link to the Python implementation only includes an encoding routine, not a decoding one, and I need to be able to decode filenames. Bit twiddling in Python is a bit beyond my current skill level, so I grabbed the decode routine from the .js example and ran it through an online language converter to get Python. I ran it and the decoded lat/long coordinates were incorrect, so I tried it with the .java and .pl examples and got the exact same incorrect results, so I assume it's something to do with the formula. Here's the code I'm using (_decode was converted from .js):
>python decode_short.py
0GAjIv8h
[1035.3722476959229, 1308.7772369384766, 16]
The encoding is correct, but the decoded values are obviously way off. Can anyone provide and hints/tips/guidance on what I should look at?
Thanks
John
I'm something of a novice Python programmer so please bear with me. OpenStreetMaps uses a 'shortlink' protocol to create file names from lat/long coordinates, which is described here: https://wiki.openstreetmap.org/wiki/Shortlink. They also include links to various coding implementations; however, the link to the Python implementation only includes an encoding routine, not a decoding one, and I need to be able to decode filenames. Bit twiddling in Python is a bit beyond my current skill level, so I grabbed the decode routine from the .js example and ran it through an online language converter to get Python. I ran it and the decoded lat/long coordinates were incorrect, so I tried it with the .java and .pl examples and got the exact same incorrect results, so I assume it's something to do with the formula. Here's the code I'm using (_decode was converted from .js):
ARRAY = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_~' import math def _encode(lat, lon, z): """given a location and zoom, return a short string representing it.""" x = int((lon + 180.0) * 2**32 / 360.0) y = int((lat + 90.0) * 2**32 / 180.0) code = _interleave(x, y) str = '' # add eight to the zoom level, which approximates an accuracy of # one pixel in a tile. for i in range(int(math.ceil((z + 8) / 3.0))): digit = (code >> (56 - 6 * i)) & 0x3f; str += ARRAY[digit] # append characters onto the end of the string to represent # partial zoom levels (characters themselves have a granularity # of 3 zoom levels). for i in range((z + 8) % 3): str += "-" return str def _decode(sc): char_array = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_~" i = 0 x = 0 y = 0 z = -8 for i in range(len(sc)): ch = sc[i] digit = char_array.index(ch) if digit == -1: break # distribute 6 bits into x and y x <<= 3 y <<= 3 for j in range(2, -1, -1): x |= (0 if (digit & (1 << (j+j+1)) == 0) else (1 << j)) y |= (0 if (digit & (1 << (j+j)) == 0) else (1 << j)) z += 3 x = x * pow(2, 2-3*i) * 90 - 180 y = y * pow(2, 2-3*i) * 45 - 90 # adjust z if i < len(sc) and sc[i] == "-": z -= 2 if i+1 < len(sc) and sc[i+1] == "-": z += 1 return [y, x, z] def _interleave(x, y): """combine 2 32 bit integers to a 64 bit integer""" c = 0 for i in range(31, 0, -1): c = (c << 1) | ((x >> i) & 1) c = (c << 1) | ((y >> i) & 1) return c encoded = _encode(50.671530961990356, 6.09715461730957, 16) print(encoded) decoded = _decode(encoded) print(decoded)Here are the results I got:
>python decode_short.py
0GAjIv8h
[1035.3722476959229, 1308.7772369384766, 16]
The encoding is correct, but the decoded values are obviously way off. Can anyone provide and hints/tips/guidance on what I should look at?
Thanks
John