Python sample of short link decode

Hi,

I’m playing around with some files created by OSMAnd which use short link file names to encode geographic location information. I’m trying to use them in an external program I’m writing in Python, but I need to decode the file names. I found the Python example at Implementation of OpenStreetmap Shortlinks in Python · GitHub, but it only contains an encode routine, and I’m not nearly a good enough Python programmer to reverse-engineer the method it uses. Can anyone point me to a Python example for decoding short link names?

Thanks

John

If anyone’s interested, the folks over at the Python forums have been extremely helpful and have provided an updated version of the shortlink decode routine that works:

def decodejs(sc):
    index_of = {x: y for y, x in enumerate("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_~")}
    x = y = 0
    z = -8
    i = 0
    for ch in sc:
        if (digit := index_of.get(ch)) is None:
            break
 
        # distribute 6 bits into x and y
        x <<= 3
        y <<= 3
        for j in range(2, -1, -1):
            if digit & 1 << (2 * j + 1):
                x |= 1 << j
            if digit & 1 << (2 * j):
                y |= 1 << j
        z += 3
        i += 1
 
    x = x * 2**(2 - 3 * i) * 90 - 180
    y = y * 2**(2 - 3 * i) * 45 - 90
 
    if i < len(sc) and sc[i] == "-":
        z -= 2
        if i + 1 < len(sc) and sc[i + 1] == "-":
            z += 1
 
    return z, y, x
 

The header of the file links to Shortlink on the OSM Wiki, where “Code for encoding & decoding” is given. Does that help?

Habi,

Thank you - that’s where I originally found the encode code, but it doesn’t contain a decode routine in Python. I’m in the process of trying out one of the online code conversion sites to see if I can translate the Javascript version to Python - we’ll see how that goes.

John

I’m hoping someone more knowledgeable in Python than I am can help me. As I mentioned I’m trying to find a sample Python implementation of a shortlink decode routing. The samples at Shortlink - OpenStreetMap Wiki only have decode routines for Java, Perl and JS, so I used some of the new online code translators to convert those decode routines into Python and tried them out, but none of them seem to work correctly. The funny thing is that all three of the routines converted from different languages gave me the exact wrong results. Here’s the code I’m using:

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) * 232 / 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
~"
x = 0
y = 0
i = 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):
x |= 0 if (digit & (1 << (2 * -j + 1))) == 0 else (1 << -j)
y |= 0 if (digit & (1 << (2 * -j))) == 0 else (1 << -j)
z += 3
x = x * 2 ** (2 - 3 * i) * 90 - 180
y = y * 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)

And here’s the results:

python decode_short.py
0GAjIv8h
[1035.3722476959229, 1308.7772369384766, 16]

(Sorry for the formatting - I can’t find a code block option in the forum interface)

Obviously the lat/long coordinates decoded are not the same as the ones encoded, but I’m not smart enough with Python to figure out where the error is happening.

Can anyone help? I’ll keep working on it but any hints/tips would be welcome.

Thanks

John