# L-15 MCS 275 Mon 18 Feb 2008 : hilbert.py

from Tkinter import *
import math

class Hilbert:
   """
   Hilbert's space filling curves
   """
   def __init__(self,wdw,dimension):
      """
      Defines a canvas, buttons, and scale.
      """
      wdw.title('Hilbert\'s space filling curves')
      self.dim = dimension # dimension of the canvas
      self.n = 1
      self.c = Canvas(wdw,width=10+self.dim,\
        height=10+self.dim,bg ='white')
      self.c.grid(row=0,column=0,columnspan=2)
      self.b = Button(wdw,text='clear',command=self.Clear)
      self.b.grid(row=1,column=1,sticky=W+E)
      self.sn = Scale(wdw,orient='horizontal',\
        from_=0,to=8,variable=self.n,command=self.Draw)
      self.sn.set(0)
      self.sn.grid(row=1,column=0,sticky=W+E)
      self.x = self.dim/2
      self.y = self.dim/2
      self.h = self.dim/4

   def A(self,k):
      """
      Turns counterclockwise from up right to down right.
      """
      if k > 0:
         self.D(k-1); self.Plot(self.x-self.h,self.y)
         self.A(k-1); self.Plot(self.x,self.y-self.h)
         self.A(k-1); self.Plot(self.x+self.h,self.y)
         self.B(k-1)

   def B(self,k):
      """
      Turns clockwise from down left to down right.
      """
      if k > 0:
         self.C(k-1); self.Plot(self.x,self.y+self.h)
         self.B(k-1); self.Plot(self.x+self.h,self.y)
         self.B(k-1); self.Plot(self.x,self.y-self.h)
         self.A(k-1)

   def C(self,k):
      """
      Turns counterclockwise from down left to up left.
      """
      if k > 0:
         self.B(k-1); self.Plot(self.x+self.h,self.y)
         self.C(k-1); self.Plot(self.x,self.y+self.h)
         self.C(k-1); self.Plot(self.x-self.h,self.y)
         self.D(k-1)

   def D(self,k):
      """
      Turns clockwise from up right to up left.
      """
      if k > 0:
         self.A(k-1); self.Plot(self.x,self.y-self.h)
         self.D(k-1); self.Plot(self.x-self.h,self.y)
         self.D(k-1); self.Plot(self.x,self.y+self.h)
         self.C(k-1)

   def Plot(self,nx,ny):
      """
      Plots a line for the current position
      to the new coordinates (nx,ny), and sets
      the current position to (nx,ny).
      """
      self.c.create_line(self.x,self.y,nx,ny,width=2)
      self.x = nx; self.y = ny

   def Draw(self,v):
      """
      Draws the Hilbert curve on canvas.
      """
      n = int(v)
      self.h = self.dim/2**n
      self.y = 5 + self.dim - self.h/2
      self.x = self.y
      self.A(n)

   def Clear(self):
      """
      Clears the canvas and resets the initial position.
      """
      self.c.delete(ALL)

def main():
   top = Tk()
   dimension = 512 # dimension of the canvas
   show = Hilbert(top,dimension)
   top.mainloop()

if __name__ == "__main__": main()
