Assignment 4 – Graphics Programming Dean Zeller CS10051 Spring, 2007 Due: Thursday, February 15th by 5:00 PM 10 points Objective The student will create pictures using a set of Python drawing procedures. Background Graphics programming is generally covered for the first time in senior-level programming classes. It is considered to be a sufficiently difficult topic to warrant covering it after programmers have some experience. This assignment is a fundamental change in that philosophy. Creating graphic pictures such as those in the examples is no more difficult than traditional programming. This assignment will give you an introduction to how programmers create works of art using a different kind of canvas. It will also serve as a stepping-stone to a computer animation assignment. Procedures Using graphics procedures in Python is very easy. Within a few lines of code, one can easily create a circle, line, polygon, rectangle, or any other shape. The challenge in graphics programming is using those procedures efficiently to produce a program interface or work of art. This is a description of the steps needed to draw basic shapes. You may first test your usage of these procedures by practicing using Python’s interactive mode. from Tkinter import * This line of code imports a library of commands for graphics programming. This should be the first line of code in your program. canvas = Canvas(width=600, height=600, bg='white') This line of code creates a Canvas object with a white background. The initial width and height are optional parameters, and the user can change the size of the window once created. Note that the canvas origin (0,0) is on the top-left corner, and the Y-coordinate moves down as y increases. While initially confusing, this is a standard in graphics programming. canvas.pack(expand=YES, fill=BOTH) To be honest, I really don’t know what the above statement does. But without it, nothing draws on the canvas. canvas.create_oval(left, top, right, bottom, width=4, fill='green') This procedure creates an oval corresponding to the given parameters of left, top, right, and bottom. The width and fill parameters can be omitted (default values 1 and 'white'). canvas.create_line(x1,y1, x2,y2, x3,y3, … xn,yn, width=3) This procedure creates a series of lines from x1,y1 to x2,y2 to x3,y3, and so on, with the specified width. Use two points for a single line. For a closed polygon, start and end on the same point. canvas.create_polygon(x1,y1, x2,y2, x3,y3, … xn,yn, fill='red1') This procedure creates a red polygon defined by the point x1,y1 to x2,y2 to x3,y3, and so on. Colors may be specified in darkness levels 1, 2, 3, and 4. canvas.create_rectangle(left, top, right, bottom, fill='orange') This procedure creates an orange rectangle defined by left, top, right, and bottom specified. right centerleft center centerright left Creating Pictures One can simply use the graphics procedures to create pictures, but top it can become cumbersome to hand-calculate every point to draw. It is far more efficient to create a Python object to draw a piece of the picture. Creating the objects with the right parameters will allow for middletop multiple drawings of the same picture at different sizes, positions, and orientations. To do this efficiently, one must use objects similar to those in the example. middle Consider the design for the stick figure. The parameters sent to the method are left, top, width, and height. The guidepoints for right, bottom, and center are calcualted middlebottom based on the parameters. Other guidepoints can be created as needed before the drawing begins. This will give the object bottom scalability. Use the example program as a template to create scalable objects. Note that a negative width or height can be specified to flip the image vertically or horizontally. height width Instructions Use Python to create one or more original works of art. There are no requirements on the tools used, but you are being graded on the artistic merit and complexity of your finished drawing. Documentation Use the program documentation to explain the history and creative thinking behind the drawing. For the object documentation, describe the picture drawn, and include comments as necessary for each piece of the picture. For the program documentation, describe the picture in general terms. Describe the bugs or strange behavior of the drawing. If something does not draw… Debugging traditional programs and graphic programs are different. There will be times an object does not appear on the canvas, even though it worked perfectly before. The following is a list of reasons an object does not draw correctly: 1. The line thickness could be 0. 2. The x and y coordinates could be off of the canvas. 3. Another drawing could be covering the missing drawing. 4. The size of the object could be 0. Turning in your Assignment Printing your artwork will involve more than just a menu command. Python does not provide a way to print a canvas. To print your work, capture your screen and paste into Word or PowerPoint. (In Windows, the Print Screen button will copy the current screen.) Print two (2) copies of your drawing(s). One will be graded and returned. Informally present your drawing(s) to the class. Grading You will be graded on the following criteria Accuracy Correctly using the graphic procedures Readability Block documentation, proper indentation, and meaningful variable names Creativity Artistic merit of the pictures created Extra Credit Present your assignment by Thursday, February 8th. Exceptional creativity in pictures created. Exceptional complexity in pictures created (e.g. create the American flag by executive order 10834) Standard proportions A B C D E F G H K L Hoist (width) of flag 1.0 Fly (length) of flag 1.9 Hoist (width) of Union 0.5385 (7/13) Fly (length) of Union 0.76 0.054 0.054 0.063 0.063 Diameter of star 0.0616 Width of stripe 0.0769 (1/13) source: Betsy Ross Homepage (http://www.ushistory.org/betsy/more/10834.htm) Japan Japan (Naval) England Canada China Ohio Djibouti South Korea ######################################################################## # # # Graphics Procedures Demonstration 1.00 # # Written by: Dean Zeller # # # # This program was written for demonstration purposes for CS10061 # # (Introduction to Programming) at Kent State University. # # (C) 2007 Dean Zeller # # # # This program is the first in a series of assignments in a # # revolutionary new style of introductory-level programming. # # Students with very little knowledge of Python programming can # # easily begin drawing pictures and animations using code similar # # to the objects found below. # ######################################################################## from Tkinter import * from whrandom import randint # import all methods from the Tkinter library # import the randint method from the whrandom library ######################################################################## # # # Stick Figure # # This object contains a method to draw a stick figure according # # to the specified parameters: # # canvas -- canvas to draw the stick figure # # left -- x-coordinate defining the left of the picture # # top -- y-coordinate defining the top of the picture # # width -- width of the picture in pixels # # height -- height of the picture in pixels # # thickness -- line thickness # # # ######################################################################## class StickFigure(object): def draw(self, canvas, left, top, width, height, thickness): # calculate guidepoints: right, bottom, center, and middle right = left + width bottom = top + height center = (left + right) / 2 middle = (top + bottom) / 2 # calculate guidepoints: centerleft, centerright, middletop, and middlebottom centerleft = (center + left) / 2 centerright = (center + right) / 2 middletop = (middle + top) / 2 middlebottom = (middle + bottom) / 2 # calculate guidepoints: legheight and armheight legheight = (middle + middlebottom)/2 armheight = (middletop + middle) / 2 # draw head canvas.create_oval(centerleft, top, centerright, middletop, width=thickness) # draw body canvas.create_line(center, middletop, center, legheight, width=thickness) # draw legs canvas.create_line(center, legheight, centerleft, bottom, width=thickness) canvas.create_line(center, legheight, centerright, bottom, width=thickness) # draw arms armheight = (middletop + middle) / 2 canvas.create_line(center, armheight, left, middletop, width=thickness) canvas.create_line(center, armheight, right, middletop, width=thickness) return ######################################################################## # # # StarOfDean # # This object contains a method to draw an amulet-style shape for # # the Star Of Dean, according to the specified parameters: # # canvas -- canvas to draw the star # # left -- x-coordinate defining the left of the picture # # top -- y-coordinate defining the top of the picture # # width -- width of the picture in pixels # # height -- height of the picture in pixels # # thickness -- line thickness # # # # HISTORICAL NOTE: My brother's name is David. As a kid, I had # # always wondered why *he* had a star ("Star of David"), but I # # did not. I have always been fond of an 8-pointed star. So I # # decided to create the infamous "Star of Dean". This object draws # # one example of the Star of Dean. As the Deanidian religion grows,# # there will be more of these stars around. # # # BUGS: It must be noted that the outer circle is outside of the # # boundary defined by left, top, width, and height. This was # # necessary for the artistic nature of the star. # # # ######################################################################## class StarOfDean(object): def draw(self, canvas, left, top, width, height, thickness): # calculate guidepoints: right, bottom, center, and middle right = left + width bottom = top + height center = (left + right) / 2 middle = (top + bottom) / 2 # calculate guidepoints: centerleft, centerright, middletop, and middlebottom centerleft = (center + left) / 2 centerright = (center + right) / 2 middletop = (middle + top) / 2 middlebottom = (middle + bottom) / 2 # draw outer circle canvas.create_oval(left-width*.06, top-height*.06, right+width*.06, bottom+height*.06, width=thickness, fill='purple3') # draw polygon and line canvas.create_polygon(centerleft, bottom, centerleft, top, right, middlebottom, left, middlebottom, centerright, top, centerright, bottom, left, middletop, right, middletop, centerleft, bottom, width=thickness, fill='blue2') canvas.create_line(centerleft, bottom, centerleft, top, right, middlebottom, left, middlebottom, centerright, top, centerright, bottom, left, middletop, right, middletop, centerleft, bottom, width=thickness) # draw inner circles canvas.create_oval(centerleft, middletop, centerright, middlebottom, width=thickness, fill='green4') canvas.create_oval(center-width*.05, middle-height*.05, center+width*.05, middle+height*.05, width=thickness) canvas.create_oval(center-width*.15, middle-height*.15, center+width*.15, middle+height*.15, width=thickness) canvas.create_oval(center-width*.35, middle-height*.35, center+width*.35, middle+height*.35, width=thickness) canvas.create_oval(center-width*.45, middle-height*.45, center+width*.45, middle+height*.45, width=thickness) return ######################################################################## # # # House # # This object contains a method to draw simple house. To # # illustrate how pictures can be within pictures, a stained-glass # # window is included using the StarOfDean object. # # canvas -- canvas to draw the house # # left -- x-coordinate defining the left of the picture # # top -- y-coordinate defining the top of the picture # # width -- width of the picture in pixels # # height -- height of the picture in pixels # # thickness -- line thickness # # color -- color of the house # # # # BUGS: At this point, the window is NOT scalable. This will # # produce strange results for small houses. # # # ######################################################################## class House(object): def draw(self, canvas, left, top, width, height, thickness, color): # calculate guidepoints: right, bottom, center, and middle right = left + width bottom = top + height center = (left + right) / 2 middle = (top + bottom) / 2 # calculate guidepoints: centerleft, centerright, middletop, and middlebottom centerleft = (center + left) / 2 centerright = (center + right) / 2 middletop = (middle + top) / 2 middlebottom = (middle + bottom) / 2 # draw the house polygon canvas.create_polygon(left, bottom, center, bottom, right, middlebottom, right, middletop, centerright, top, centerleft, middletop, left, middle, left, bottom, fill=color) # draw the house lines canvas.create_line(left, bottom, center, bottom, right, middlebottom, right, middletop, center, middle, center, bottom, center, middle, left, middle, left, bottom, left, middle, centerleft, middletop, center, middle, centerleft, middletop, centerright, top, right, middletop, width=thickness) # draw the stained-glass window window = StarOfDean() window.draw(canvas, centerleft-15, middletop+15, 30, 30, 1) return ######################################################################## # # # Main program -- ZellerTown # # This program creates the picture for a typical day in ZellerTown. # # Using the StickFigure, StarOfDean, and House objects defined # # above, several town figures, houses, a sun, and a demon-summoning # # altar are drawn. # # # ######################################################################## # create canvas canvas = Canvas(width=600, height=600, bg='tan') canvas.pack(expand=YES, fill=BOTH) # define objects townsfolk = StickFigure() star = StarOfDean() house = House() # draw picture piecewise, allowing user to control flow raw_input("Press return to draw a stickfigure") townsfolk.draw(canvas,50,450,50,100,3) raw_input("Press return to draw the sun") star.draw(canvas,500,5,100,100,2) raw_input("Press return to draw an evil magician doing a demon summoning ritual") star.draw(canvas,150,350,200,100,2) townsfolk.draw(canvas,235,315,50,75,3) raw_input("Press return to draw some houses.") house.draw(canvas,400,300,200,200,3,'red4') house.draw(canvas,300,50,-275,250,4,'orange3') house.draw(canvas,400,200,100,100,2,'white') house.draw(canvas,-50,250,200,100,3,'yellow2') raw_input("Press return to draw a fiddler on the roof!") townsfolk.draw(canvas,515,285,25,50,2) print "Thank you!" VROOM!!! Stop We Have Visitors designed by Dean Zeller drawn by Zhiyong Yang designed by Dean Zeller drawn by Zhiyong Yang designed by Dean Zeller drawn by Zhiyong Yang Lightning Fast designed by Dean Zeller drawn by Zhiyong Yang My Washing Bottle designed and drawn by Zhiyong Yang Have a Mad Day designed by Dean Zeller drawn by Zhiyong Yang Tanks for the Memories Plane designed and drawn by David Amon designed and drawn by David Amon Down the Tracks designed and drawn by Josh Myers My Pet designed and drawn by Zhiyong Yang Double Happy designed and drawn by Zhiyong Yang On the Bridge designed and drawn by Josh Myers