CSC 15 Lab 2 Due BEFORE next week's lab session. The central purpose of this lab is to demonstrate the advantage of making your programs *abstract* by using variables. For this assignment you are to draw a stick figure like the one shown in class. It should have at a minimum a round head, nose, mouth, torso, arms, and legs. ********************************************* You should complete the coordinate calculations of the stick figure worksheet given to you separately before coding. ********************************************* First download the skeleton program diamond.py. The only parts of this program that you need to change are the initialization of the variables width, height, and the contents of the "mydraw" procedure, which currently draws a blue diamond. You need to change it so that it draws a stick figure (erase or comment out the original code). The object 'brush' manages the drawing of shapes onto a display area. You can use the following basic drawing statements in your code: brush.set_source_rgb(0,0,1) # sets drawing color in (Red,Green,Blue, 0-1) brush.move_to(x,y-scale) # moves drawing pen to coordinates brush.line_to(x+scale,y) # draws line to coordinates For example, to draw a line between coordinates x1,y1 and x2,y2, you can do brush.move_to(x1,y1) brush.line_to(x2,y2) The current position is now at x2,y2, so if you want to draw another line from from here, there's no need to call another .move_to. In other words, as long as you're drawing connected lines, there's no need to call .moveto(..) between calls to .line_to(..). However, if you want to stop drawing connected lines and want to draw a new line at a completely different coordinate, you need to call .move_to first. Drawing a circle is a bit more complicated and takes two lines: brush.new_sub_path() brush.arc(x,y,radius,0,2*pi) This draws a circle, centered at x,y, of given radius (in pixels). Using pi here assumes you have 'from math import pi' at the beginning of the program. Otherwise, use 3.1415927 for pi. Finally, the call to brush.stroke() actually renders the drawing: this can just be the last line inside the mydraw procedure. Be sure that your code is indented correctly inside the mydraw function. I recommend drawing the body parts of the figure first and work on the head last. The head (eyes, nose, mouth) is harder. These are all the technical elements you need to complete the basic assingment, but you can also experiment with other drawing procedures: brush.rectangle(x,y,w,h) draws a rectangle with to left-hand corner at x,y and has w width and h height. brush.fill() # if executed after a call to .rectangle or .arc, will draw a solid rectangle or arc. Consult https://cairographics.org/documentation/pycairo/2/reference/context.html For more procedures that you can call. After drawing the basic figure, CHANGE the values of the x, y and scale variables and make sure that your program still works: please don't scare the kids with a dismembered figure! ############################## PART II ################################ For the second part of the assignment, you need to add (at least) three additional variables to control the positions of the left arm, right arm, and mouth. The variables should allow each of the arms to be in one of three positions: up, down or straight. The mouth should be in at least two positions: smile or frown. The variables should contain integer values. You need to figure out how to change the formulas that calculate the coordinates to factor in these variables - and for those of you who have done some programming, DO NOT use if-else statements as they should not be needed. Hint: the arm variables should have one of three values: -1, 0 or 1 ################### COMMENTING ################### Comments are an important part of any serious program and you are required to comment. Your comments should be clear as to what part of the anatomy you're drawing with each statement. If you have additional code, you need to comment on what they're for too. Also make sure that ALL VARIABLES ARE CLEARLY COMMENTED. That is, describe the role of the variable in your program in english. For example # integer larmpos controls the position of the left arm larmpos = 1 Writing down the type (integer) of the variable is a good idea. Here's a BAD way to comment: l = 0 # assigns l to 0 It's a bad comment because it doesn't help us to understand the program any better. Also, using l as a variable name is a bad idea: looking at it gives us no clue as to what it represents, and it can easily be mistaken for a 1 (one). Also don't use the letter O as a variable name as it can be mistaken for 0. It's ok to use x,y to represent coordinates, however, because that's what they're traditionally used for. How much commenting is enough? Imagine yourself looking at your code a year from now. Would you be able to understand it? Comment as much as possible. Also, don't expect much help from the professor or the tutor if your code isn't commented. ############################ Adding Animation ######################### This part of the assignment will require you to use while loops. After you have code that can draws a figure, and which uses the variables adequately, you can create an animation by moving your code into the 'basic animation template' program found on the class webpage. The only part of this program that you should change is inside the 'mydraw' procedure (between def mydraw(): and #mydraw). The code already there animates a simple rectangle. You have to modify the while loop to animate your stick figure by changing some of your variables that controls the figure after each time that the figure is drawn. The last two lines inside the while loop must remain as updateDisplay() # renders image to screen. time.sleep(0.2) # delay for 0.2 seconds The first line draws your figure to the screen. Individual calls to brush.line_to, brush.arc, etc are 'buffered' before this call is made. This makes the animation look much smoother. The second line delays the program by a specified amount of time. You can change the 0.2 to something else so the animation doesn't run too fast. The human eye can only see about 30 frames per second, so don't make this value smaller than 0.033. Make sure that your code is propery indented relative to the mydraw procedure and the while loop. You can make your program more interesting by using random numbers: from random import randint # this should be at the top of your porgram r = randint(-5,5) # generates random integer between -5 and 5 inclusively. CHALLENGE: Write a program that moves the figure around randomly, WRAPPING AROUND the edges of the window. Use % instead of if statements. MEGACHALLENGE: Instead of wrapping around the edges of the window, have the figure bounce off the edges. GIGACHALLENGE: research how to use the .translate and .transform commands to rotate the figure to be at any angle. You should try to rotate the figure relative to its own center. This will also require you to learn how to use a cairo.Matrix, and call rotate on it. Follow the links in the documentation (URL above). TERACHALLENGE: Instead of using .translate and .transform, use trignometry from scratch. If you import math, then you can call math.sin, math.cos, math.tan, and math.atan (arctangent). Angles are in radians (math.pi == 180 degrees). Write a general procedure def rotate(cx,cy,x,y,deg) that rotates x,y around center point cx,cy by deg degrees. ############################ Other things to note. In Python3 there are two operations for division, 4/2 returns 2.0 even though both 4 and 2 are integers. 5//2, however, will return 2, which is the integer quotient without the remainder (the remainder itself can be obtained with 5%2). I recommend using //, which always returns an integer (and is consistent with how most other languages work). Just be careful: write 3*scale//4, and not 3//4*scale (why?). ######################### Killing Zombies ######################### Graphical programs sometimes don't terminate properly, especially if you try to interrupt them. To stop a graphical program, if you can't close the window, try Control-c, or Control-z in the terminal window where you ran the program. Control-z doesn't really terminate the program but rather suspends it. You will see a message like [2]+ Stopped python3 program.py The stopped program can be resumed, but you probably don't want to because it might just bite you and turn you into one of them. To kill it, do: kill -9 %2 The number after the % symbol should be the same as the number inside [ ] in the message. You can also use the 'jobs' shell command to list all running and suspended processes. The scary sounding 'kill' command sends an interrupt signal to the running process, and -9 signals the process to terminate.