Some tasks require to you to communicate or store your geographical location. In a local application, you can store it as two floating point numbers and never worry about anything else.

For this purpose, we can use Quadtiles. In our Python program, we can represent a quadtile as the four corners of a rectangular area. I’ll call these xFrom, xTo, yFrom and yTo, but it might be more accurate to use terminology like latitude and longitude.

In [2]:

Quadtiles are about splitting the current Quad into 4 tiles, picking one of them and repeating. Since we want to be able to point to any location on Earth, our initial Quad will always be the whole world.

In [3]:
WORLD = Quadtile(-180, 180, 90, -90)

WORLD
Out [3]:

### Getting the center point

When working with locations, we often need a single point instead of a Quad, so let’s write a function to get the center point. We will calculate this by getting the midpoint value of the X and Y ranges.

In [4]:
return (x, y)
In [5]:
Out [5]:
(0.0, 0.0)

Makes sense, the center of the world is at (0, 0). This is the value we will get when we try to compute the location represented by the empty string, i.e. the default location.

In [6]:
if right:
xf = mid
else:
xt = mid

Out [6]:
(-90.0, 0.0)
Out [6]:
(90.0, 0.0)

Now let’s do it in the other axis.

In [7]:
if not bottom:
yf = mid
else:
yt = mid

Out [7]:
(0.0, -45.0)
Out [7]:
(0.0, 45.0)

## A simple encoding

blah blah blah

In [8]:
def decode_bits(bits):
is_x = True

for bit in bits:
bit = int(bit)

if is_x:
else:

is_x = not is_x

decode_bits("01001")
decode_bits("01100111")
Out [8]:
(-112.5, 22.5)
Out [8]:
(-56.25, 39.375)

Blah blah blah

In [10]:
def encode_location(coord, N):
bits = ""
x, y = coord

is_x = True

for i in range(N):
if is_x:
if x > mid[0]:
bit = 1
else:
bit = 0
else:
if y > mid[1]:
bit = 1
else:
bit = 0
bits += str(bit)
is_x = not is_x

return bits

Let’s make a plot of how accurate our positions gets with more bits added. Lower numbers are more accurate.

## Map visualizations

In [11]:
HOUSE = (-8.577507, 52.664838)
In [12]:
def plot_path(path, zoom):
print(f"Path length: {len(path)}")
fig, ax = plt.subplots(figsize=(8, 8), dpi=100)
ax.xaxis.set_visible(False)
ax.yaxis.set_visible(False)

xs = [0.5]
ys = [0.5]

bits = ""
for bit in path:
bits += bit
x, y = decode_bits(bits)
x, y = tilemapbase.project(x, y)
xs.append(x)
ys.append(y)

extent = tilemapbase.Extent.from_centre_lonlat(*decode_bits(bits), xsize=zoom)
extent = extent.to_aspect(1.0)

plotter = tilemapbase.Plotter(extent, t, width=400)
plotter.plot(ax, t)

_ = ax.plot(xs, ys)
plt.show()
In [13]:
plot_path(encode_location(HOUSE, 8), 0.55)
Out:
Path length: 8
Out:

We can see that 8 bits is enough to get us next to the correct country. Let’s do the same for getting to the city.

In [14]:
plot_path(encode_location(HOUSE, 16), 0.01)
Out:
Path length: 16
Out:

16 bits (2 bytes) gets us in the county, really close to the actual city. Let’s keep going.

In [15]:
plot_path(encode_location(HOUSE, 24), 0.008)
plot_path(encode_location(HOUSE, 24), 0.0005)
Out:
Path length: 24
Out: