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
