########### Skeleton Program for CSC 15 Recursion Lab ############ # This program draws a very uninteresting triangle. It uses the same drawing # and animation that we've used previously for the horserace and other # programs. Find the 'mydraw' function below. This time I've written a # *local function* inside mydraw, called 'triangles'. When a function is # defined locally within a function in Python, it is only useable from within # the containing function. Furthermore, the local variables of the containing # function (in this case gc, brush) are visible inside the sub-function. # Right now the function draws a large isosceles triangle. Your assignment # is to make the triangles function RECURSIVE so that it draws many triangles # within triangles, with a naturally recurring pattern. The result is called # a Sierpinski Triangle. # A triangle is defined by tree points: top (x1,y1), left base (x2,y2) and # right base (x3,y3). These form the parameters to the triangles function. # We can break a large triangle into three smaller triangles by # identifying the three mid-points on the three sides of the triangle. For # example, the midpoint between (x1,y1) and (x2,y2) is (mx,my) where # mx is (x1+x2)/2 and my is (y1+y2)/2. The midpoints allow us to divide # the triangle into three smaller triangles. That is, they allow us to # make recursive calls that draw the three smaller triangles. # The recursion should stop when the size of the triangle is too small # (experiment). # You can modify the 'delaytime' variable below to change the speed of animation # Triangle program base import pygtk import gtk import gobject import time import threading from random import * from math import * width,height = 800,700 delaytime = 16 # millisecond delay between animation frames window = gtk.Window(gtk.WINDOW_TOPLEVEL) window.set_title("Simplified Drawing Example") window.connect("destroy", lambda w: gtk.main_quit()) area = gtk.DrawingArea() area.set_size_request(width+10,height+10) window.resize(width+10,height+10) window.add(area) window.show_all() window.move(0,0) gc0 = area.window.new_gc() cmap = gc0.get_colormap() # common colors green = cmap.alloc_color(red=0,green=65535,blue=0) blue = cmap.alloc_color(red=0,green=0,blue=65535) red = cmap.alloc_color(red=65535,green=0,blue=0) white = cmap.alloc_color("white") black = cmap.alloc_color("black") gray = cmap.alloc_color("gray") yellow = cmap.alloc_color("yellow") purple = cmap.alloc_color("purple") gc0.set_foreground(green) gc0.set_background(blue) gc0.line_width = 1 # double buffering setup dbuf = gtk.gdk.Pixmap(area.window,width+10,height+10,-1) gc1 = dbuf.new_gc() gc1.set_colormap(cmap) ### Thread control syn = threading.Event() # throttles mainloop syn2 = threading.Event() # throttles user thread syn.clear() syn2.clear() stopall = False # for cleanup class MyThread ( threading.Thread ): def __init__(self,brush,gc): self.win = brush self.dgc = gc threading.Thread.__init__(self) def run ( self ): global mydraw mydraw(self.win,self.dgc) eehandler = 0 def area_expose_cb(area, event): global mainloop,eehandler my = MyThread(dbuf,gc1) my.start() # start student thread, which calls mydraw area.handler_block(eehandler) # prevent restart when window moves. mainloop(area.window) # start main animation refresh cycle return True # get ready for expose event eehandler = area.connect("expose_event", area_expose_cb) # animation refresh control loop: def mainloop(brush): if not stopall: syn.wait() # wait for permission to refresh screen syn.clear() # reset for next round brush.draw_drawable(gc0,dbuf,0,0,0,0,width+10,height+10) # refresh syn2.set() # informs user thread to goto next iteration eid = gobject.timeout_add(delaytime, mainloop, brush) # reschedule return False # end mainloop def updateDisplay(): syn.set() # release mainloop to refresh screen syn2.wait() # synch with mainloop before looping again syn2.clear() # reset for next round # end updateDisplay def cleanup(): global stopall stopall = True syn.set() syn2.set() # end cleanup # easier to use functions for drawing circle/sphere def drawcircle(brush,gc,x,y,radius,fill): brush.draw_arc(gc,fill,x-radius,y-radius,2*radius,2*radius,0,360*64) ## Some might-be useful functions # function to wrap around (returns new x,y coordinate) def wraparound(x,y,radius): if (x(width-radius)): x = radius # right to left if (y(height-radius)): y = radius # bottom to top return (x,y) #wraparound # distance function def dist(x1,y1,x2,y2): dx = x1-x2 dy = y1-y2 return (dx*dx + dy*dy)**0.5 #dist ######################## YOUR CODE GOES BELOW ############################ # Note that the triangles function is defined inside the mydraw function: # this menas that it has access to the variables brush and gc, which are # local within mydraw. ##### # A function called 'mydraw' must be defined: def mydraw(brush,gc): def triangles(x1,y1,x2,y2,x3,y3): # MODIFY THIS FUNCTION**** gc.set_foreground(red) brush.draw_line(gc,x1,y1,x2,y2) gc.set_foreground(green) brush.draw_line(gc,x2,y2,x3,y3) gc.set_foreground(blue) brush.draw_line(gc,x3,y3,x1,y1) updateDisplay() # end of triangles local function definition gc.set_foreground(white) # Erase previous image brush.draw_rectangle(gc,True,0,0,width+10,height+10) updateDisplay() # call at end of anim triangles(width/2,0,0,height,width,height) # calls triangles function. # cleanup() #end mydraw ########################################################################## # The following line must be the last line in the program gtk.main()