
# hilbert.py
# Andrew Davison, ad@coe.psu.ac.th, April 2025
# https://en.wikipedia.org/wiki/Hilbert_curve
'''
Draw a 2d Hilbert curve by rotating, reflecting, translating
and scaling four copies of H_(n-1) to get H_n. 

The composition of the four 'curves' is easy since each
is represented by a list of coordinates. 

For the more usual recursive four-functions definition
using the Turtle module for drawing, see Sec 7.1. Fractals
'''

import math
import matplotlib.pyplot as plt
from HC2Mat import *

L = 50   # length of one side of H1


def transformCurve(h):
  # Use hilbert curve h to generate next one

  # build parts in 4 quadrants
  m = multMatsList([ transMat(L,L), 
                 reflectXMat(), rotMat(-90) ]) 
  ne = [applyMat(m, c) for c in h]  # north east quadrant
  
  se = [applyMat(transMat(L,-L), c) for c in h]
  
  sw = [applyMat(transMat(-L,-L), c) for c in h]
  
  m = multMatsList([ transMat(-L,L), 
                 reflectXMat(), rotMat(90) ]) 
  nw = [applyMat(m, c) for c in h]
  
  hNew = ne + se + sw + nw # concatenate parts
  return [applyMat(scaleMat(0.5,0.5), c) for c in hNew]


# -------------------------------------

hOrder = int(input("Hilbert curve order (1-6)? "))

fig, ax = plt.subplots(figsize=(6, 6))
ax.set_aspect('equal')
ax.set_xlim(-L, L)
ax.set_ylim(-L, L)
ax.axis('off')

h = [ (L/2,L/2), (L/2,-L/2), (-L/2,-L/2), (-L/2,L/2)]  
      # H1, centered on origin (a U-shape)
for i in range(hOrder-1):
  h = transformCurve(h)

xs, ys = zip(*h)
ax.plot(xs, ys, lw=0.5)

plt.title(f"Hilbert Curve {hOrder}")
plt.show()
