- mapplotlib
- numpy
$ python morton-plot.py
$ python morton-plot.py --revert
import argparse | |
import numpy as np | |
import matplotlib.pyplot as plt | |
import matplotlib.animation as animation | |
from itertools import islice | |
parser = argparse.ArgumentParser() | |
parser.add_argument('--revert', action='store_true') | |
args = parser.parse_args() | |
NUM_POINTS = 1000 | |
LIMIT = 100 | |
def part1_by1(x): | |
x &= 0x0000ffff | |
x = (x ^ (x << 8)) & 0x00ff00ff | |
x = (x ^ (x << 4)) & 0x0f0f0f0f | |
x = (x ^ (x << 2)) & 0x33333333 | |
x = (x ^ (x << 1)) & 0x55555555 | |
return x | |
def part_even(x): | |
x = x & 0x5555555555555555 | |
x = (x | (x >> 1)) & 0x3333333333333333 | |
x = (x | (x >> 2)) & 0x0F0F0F0F0F0F0F0F | |
x = (x | (x >> 4)) & 0x00FF00FF00FF00FF | |
x = (x | (x >> 8)) & 0x0000FFFF0000FFFF | |
return x | |
def encode_morton_2d(x, y): | |
code = (part1_by1(y) << 1) + part1_by1(x) | |
return code | |
def decode_morton_2d(code): | |
x = part_even(code) | |
y = part_even(code >> 1) | |
return x, y | |
def revert_morton(code): | |
code = ((code >> 1) & 0x55555555) | ((code & 0x55555555) << 1) | |
code = ((code >> 2) & 0x33333333) | ((code & 0x33333333) << 2) | |
code = ((code >> 4) & 0x0f0f0f0f) | ((code & 0x0f0f0f0f) << 4) | |
code = ((code >> 8) & 0x00ff00ff) | ((code & 0x00ff00ff) << 8) | |
code = ((code >> 16) & 0xffff) | ((code & 0xffff) << 16) | |
return code | |
def identity(code): | |
return code | |
a = np.random.randint(1, 100, size=(NUM_POINTS, 2)) | |
func = revert_morton if args.revert else identity | |
codes = ((p[0], p[1], func(encode_morton_2d(p[0], p[1]))) for p in a) | |
codes_sorted = sorted(codes, key=lambda c: c[2]) | |
b = np.array(list([c[0], c[1]] for c in islice(codes_sorted, LIMIT))) | |
def update_line(num, data, line): | |
line.set_data(data[:num, 0], data[:num, 1]) | |
return line, | |
fig = plt.figure() | |
plt.plot(a[:, 0], a[:, 1], 'b.') | |
plt.title('Revert Morton' if args.revert else 'Morton') | |
l, = plt.plot([], [], 'ro') | |
anim = animation.FuncAnimation(fig, update_line, LIMIT, fargs=(b, l), | |
interval=50, blit=True, repeat=False) | |
anim.save('{}morton.mp4'.format('revert' if args.revert else '')) | |
plt.show() |