#!/usr/bin/env python # Rotating Diamonds import pygtk import gtk import gobject import time import threading from random import randint from math import * width,height = 900,700 delaytime = 70 # 100ms 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,height) window.resize(width,height) 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,height,-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 # Thread permits a while loop inside mydraw 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) 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 moved. mainloop(area.window) # sxxtart 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,height) # 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 ########################################################################## def drawcircle(brush,gc,x,y,radius,fill): brush.draw_arc(gc,fill,x-radius,y-radius,2*radius,2*radius,0,360*64) def drawcircle(brush,x,y,radius,fill): brush.draw_arc(gc1,fill,x-radius,y-radius,2*radius,2*radius,0,360*64) # distance: def dist(x1,y1,x2,y2): dx = x1-x2 dy = y1-y2 return (dx*dx + dy*dy)**0.5 # make sure coordinates stay within width, height: def inbounds(x,y): if (x<15): x = width-15 if (x>(width-15)): x = 15 if (y<15): y = height-15 if (y>height-15): y = 15 return (x,y) # return the tuple x,y # end inbounds ### rotation of a point about a center point: # x,y: center point, angle = degree of counter-clockwise rotation # returns tuple representing rotated point def rotate(point,x,y,angle): nx,ny = point[0]-x, point[1]-y # origin offset nxcopy = nx r = angle/180.0*pi # degree in radians nx = nx*cos(r) + ny*sin(r) # must use original nx ny = ny*cos(r) - nxcopy*sin(r) #*-1 + ny*cos(r) nx,ny = nx + x, ny+y # origin offset readjustment return (int(nx+0.5),int(ny+0.5)) # rotation of a single point def drawdiamond(brush,gc,x,y,scale,dcolor,ra): gc.set_foreground(dcolor) top = (x,y-scale) left = (x-scale,y) right = (x+scale,y) bottom = (x,y+scale) rx,ry = top[0],top[1] # point of rotation top = rotate(top,rx,ry,ra) left = rotate(left,rx,ry,ra) right = rotate(right,rx,ry,ra) bottom = rotate(bottom,rx,ry,ra) brush.draw_line(gc,top[0],top[1],left[0],left[1]) # upper left brush.draw_line(gc,left[0],left[1],bottom[0],bottom[1]) # lower left brush.draw_line(gc,bottom[0],bottom[1],right[0],right[1]) # lower right brush.draw_line(gc,right[0],right[1],top[0],top[1]) # upper right # drawdiamond # main animation procedure MUST be called mydraw #################### YOUR CODE GOES HERE ###################### def mydraw(brush,gc): x = 80 # center coordinates y = 200 scale = 100 # size ra = 0 # angle of rotation (counterclockwise) while x<=width: gc.set_foreground(white) # sets drawing color brush.draw_rectangle(gc,True,0,0,width,height) # clear background drawdiamond(brush,gc,x,y,scale,blue,360-ra) x = x+2 # scale = scale-8 ra = (ra+5) % 360 updateDisplay() # show animation frame (call at end of while loop) #end animation loop cleanup() # should be called after end of all animation # end mydraw ########################################################################## # The following line must be the last line in the program gtk.main()