# hilbert.py # Walker M. White (wmw2) # Based on an module write by Dexter Kozen # October 14, 2014 from tkturtle import * import math """Module to draw cool shapes with the TkTurtle.""" #################### Hilbert Curves #################### def hilbert(w, d, n, sp=0): """Remove all drawings from the graphics window and draw a magenta Hilbert curve with side length d and depth n. sp is the speed of the drawing turtle. Precondition: w is a tkturtle Window object. d > 0 is a number (int or float). n >= 0 is an int. sp is an int in the range 0..n.""" assert type(w) == Window, `w`+' is not a window object' assert type(d) in [int, float] and d > 0, `d`+' is not a valid length' assert type(n) == int and n >= 0, `n`+' is not a valid n' assert type(sp) == int and 0 <= sp <= 10, `sp`+' is not a valid Turtle speed' # Create the turtle w.clear() t = Turtle(w) t.color = 'magenta' t.speed = sp # Get the turtle in position w/o drawing t.move(-d/2.0,-d/2.0) t.right(90) # Draw the Hilbert curve hilbert_helper(t, d, n, False); t.visible = False def hilbert_helper(t, d, n, reverse): """Using Turtle t, draw a Hilbert curve of size d and depth n. The curve is draw right to left if reverse is true. Otherwise, it is drawn left to right (we need this feature to smoothly draw the recursive Hilbert curves). If drawing in reverse, the Turtle starts on the right side. Otherwise, it start on the left. Precondition: t is a Turtle with drawmode True. d >= 0 is a number. n >= 0 is an int. reverse is a bool.""" # DO NOT WORRY ABOUT ENFORCING IN THE HELPER # Turning directions depend on whether or not we are in reverse if reverse: angle = -90 else: angle = 90 # BASE CASE: d = 0 if n == 0: t.forward(d) t.right(angle) t.forward(d) t.right(angle) t.forward(d) return # Compute what the grid looks like dotsize = (2**(n+1))-1 # Number of dots in grid subsize = (2**n)-1 # Number of dots for each sub-hilbert # Compute the new edge sizes. factor = (subsize)/float(dotsize) side = d*factor edge = d-2*side # Recursively draw the curve. t.right(angle) hilbert_helper(t,side,n-1,not reverse) t.right(angle) t.forward(edge) hilbert_helper(t,side,n-1,reverse) t.left(angle) t.forward(edge) t.left(angle) hilbert_helper(t,side,n-1,reverse) t.forward(edge) t.right(angle) hilbert_helper(t,side,n-1,not reverse) t.right(angle) ################ Sierpinski Carpet ################# # This is a fun additional example to play with. def sierpinski_carpet(w, s, n): """Remove all drawings from the window and draw a Sierpinksi carpet with side length s, depth n, and bottom left corner (0, 0), using a newly created Pen (NOT Turtle). The pen is hidden during drawing and left hidden at the end. Precondition: w is a cturtle Window object. n >= 0 is an int and s > 0 a float.""" w.clear() p = Pen(w) # initially at (0,0) p.move(-s/2,-s/2) p.visible = False # Draw the initial solid square at (0,0) fill_square(p,s) # Fill in white squares p.fillcolor = 'white' sierpinski_carpet_helper(p, -s/2, -s/2, s, n); def sierpinski_carpet_helper(p, x, y, s, n): """Using pen p, draw a Sierpinksi carpet of depth n with side length s and bottom left corner (x, y). Precondition: p is a Pen with fill attribute False. x and y are floats. n >= 0 is an int and s > 0 a float.""" if n == 0: return p.move(x+s/3, y+s/3) fill_square(p,s/3) # Fill in the 8 squares with d-1-level carpets # They are 00 01 02 # 10 12 # 20 21 22 sides = [0, 1, 2] for a in sides: for b in sides: if not (a==1 and b ==1): sierpinski_carpet_helper(p, x+a*s/3, y+b*s/3, s/3, n-1); # Useful helper function def fill_square(p,s): """Using pen p, fill a square with side length s, with bottom-left corner given by p's current position Precondition: p is a Pen with fill attribute False. s > 0 is a float.""" p.fill = True p.drawLine(s, 0) p.drawLine(0, s) p.drawLine(-s, 0) p.drawLine(0, -s) p.fill = False ################ Test Function ################# def main(): """Run each of the functions, pausing for a key press at each step""" w = Window() print 'Calling Hilbert n=3' hilbert(w, 300, 3) raw_input('Hit ') print 'Calling Hilbert n=4' hilbert(w, 300, 4) raw_input('Hit ') print 'Calling Sierpinski n=3' sierpinski_carpet(w, 300, 3) raw_input('Hit ') print 'Calling Sierpinski n=4' sierpinski_carpet(w, 300, 4) raw_input('Hit ') # Application code if __name__ == '__main__': main()