Hilbert Curve on the Unicorn HAT


#1

I was fascinated by the Hilbert curve and looking for something different to display using my Unicorn HAT.

After a fair bit of reading, researching, drawing and a lot of trial and error I came up with the following python code (lots of which came from https://people.sc.fsu.edu/~jburkardt/py_src/hilbert_curve/hilbert_curve.html).

I hope this proves interesting/uesful to someone else.

#! /usr/bin/env python

##  Hilbert_Chase.py

##  Author  :  Craig Thomas (Honorable mention to John Burkardt for the complex maths)
##  Created :  2017.03.27

##  Inspired by the Raspberry Pi, Unicorn HAT and the Hilbert Curve
#   https://en.wikipedia.org/wiki/Hilbert_curve

##  John Burkardt's code
#   https://people.sc.fsu.edu/~jburkardt/py_src/hilbert_curve/hilbert_curve.html

##  Other Useful links:
#   https://shop.pimoroni.com/products/unicorn-hat
#   https://github.com/pimoroni/unicorn-hat
#   https://learn.pimoroni.com/tutorial/unicorn-hat/making-rainbows-with-unicorn-hat




# Import statements

import unicornhat as uh
import colorsys as col
import time



def d2xy ( m, d ):

#*****************************************************************************80
#
## D2XY converts a 1D Hilbert coordinate to a 2D Cartesian coordinate.
#
#  Licensing:
#
#    This code is distributed under the GNU LGPL license. 
#
#  Modified:
#
#    03 January 2016
#
#  Parameters:
#
#    Input, integer M, the index of the Hilbert curve.
#    The number of cells is N=2^M.
#    0 < M.
#
#    Input, integer D, the Hilbert coordinate of the cell.
#    0 <= D < N * N.
#
#    Output, integer X, Y, the Cartesian coordinates of the cell.
#    0 <= X, Y < N.
#
  n = 2 ** m

  x = 0
  y = 0
  t = d
  s = 1

  while ( s < n ):

	rx = ( ( t // 2 ) % 2 )
	if ( rx == 0 ):
	  ry = ( t % 2 )
	else:
	  ry = ( ( t ^ rx ) % 2 )
	x, y = rot ( s, x, y, rx, ry )
	x = x + s * rx
	y = y + s * ry
	t = ( t // 4 )

	s = s * 2

  return x, y


  
  
def rot ( n, x, y, rx, ry ):

#*****************************************************************************80
#
## ROT rotates and flips a quadrant appropriately.
#
#  Licensing:
#
#    This code is distributed under the GNU LGPL license. 
#
#  Modified:
#
#    03 January 2016
#
#  Parameters:
#
#    Input, integer N, the length of a side of the square.  
#    N must be a power of 2.
#
#    Input/output, integer X, Y, the coordinates of a point.
#
#    Input, integer RX, RY, ???
#
  if ( ry == 0 ):
#
#  Reflect.
#
	if ( rx == 1 ):
	  x = n - 1 - x
	  y = n - 1 - y
#
#  Flip.
#
	t = x
	x = y
	y = t

  return x, y

  
 
  
  
def timestamp ( ):

#*****************************************************************************80
#
## TIMESTAMP prints the date as a timestamp.
#
#  Licensing:
#
#    This code is distributed under the GNU LGPL license. 
#
#  Modified:
#
#    06 April 2013
#
#  Author:
#
#    John Burkardt
#
#  Parameters:
#
#    None
#
  import time

  t = time.time ( )
  print ( time.ctime ( t ) )

  return None

  


def draw ( x, y, r=255, g=0, b=0 ):
	# Function to draw a pixel a particular colour on the unicorn HAT and pause
	
	uh.set_pixel(x,y,r,g,b)
	uh.show()				# Show the new pixel
	time.sleep( 1.0 / 10 )	# Pause for 1/10th of a second
	
	return		# End def draw
	
	
def d2xy_walk ( ):

#*****************************************************************************80
#
## D2XY_WALK runs D2XY.
#
	# Partly my function
	
	# import platform
	#import unicornhat as uh
	#from time import sleep
	#import colorsys

	m = 3
	n = 2 ** m

	print ( '' )
	print ( '    D    X    Y    R    G    B' )
	print ( '' )
	
	huemax = 10		# Number of steps in hue to take to cover the entire range
	for hue in range ( 0 , huemax ):
		# For each hue step
		
		for d in range ( 0, n * n ):
			# For each pixel
			
			x, y = d2xy ( m, d )	# Get location on grid
			rgb = col.hsv_to_rgb( (1.0 * hue) / huemax, 1.0, 1.0 )		# Convert HSV stepped colour to RGB
			r = int( round (255 * rgb[0] ) )		# Set R, G and B values
			g = int( round (255 * rgb[1] ) )
			b = int( round (255 * rgb[2] ) )
			draw ( x, y, r, g, b )		# Draw the coloured pixel
			print ( '  %3d  %3d  %3d  %3d  %3d  %3d' % ( d, x, y, r, g, b ) )	# Text Output (debugging)
			
		# End for d
		
	# End for hue
	
	print ( '' )

	return		# End def d2xy_walk
  
  


#*****************************************************************************80
#
## The MAIN program starts HERE
  

# If being run as the primary program (not a module)  
if ( __name__ == '__main__' ):

	# Set up Unicorn HAT
	
	uh.set_layout(uh.HAT)				# Set layout to 8x8 Unicorn HAT - Default anyway?
	u_width,u_height=uh.get_shape()		# Get the shape

	uh.rotation(0)						# Set rotation
	uh.brightness(0.5)					# Set the brightness
	uh.off								# Clear the board
	
	timestamp ( )		# Timestamp the start

	# Run the Walk?
	d2xy_walk ()
	
	timestamp ( )		# Timestamp the end
  

## End of the File

#2

A quick video here:

https://youtu.be/9zOoEJ1veJI


#3

I am a mathematician so this appeals to me a lot. Good job. Thanks for sharing.

This reminds me off an arduino project I did years ago: a 128x64 Graphic LCD which played Conway’s game of life continuously. You inspired me to resuscitate that project.

Cheers.