Homework 2b - Quilt

For this project, you'll write code that draws lines, ovals etc. on screen to make some neat patterns. All parts of HW2 are due Wed Oct 9th 11:55 p.m.

To get started, download quilt.zip. Open that .zip file to get a "quilt" folder containing the quilt.py file for this program. Open the quilt folder with the PyCharm open... menu command to get started.


When a Python program runs, the special main() is the first to run, and it calls other functions. For the quilt program, we provide working main() function. Depending on the command line arguments, main() calls one or another of your functions as shown below.

The quilt drawing is made of three different "patch" drawings: bars, eye, and bowtie. Each patch type is drawn by its own function, and these functions are the first three parts of the project.

a. draw_bars()

def draw_bars(canvas, x, y, width, height, n):

This function draws a rectangle and then a series vertical bars (see examples below).

1. Draw a rectangle on the passed in canvas with its upper left corner at the given x,y and extending the given width and height. Draw the rectangle with a light blue color by adding this optional named parameter when calling draw_rect: color='lightblue'

All of the patches we draw will have this lightblue border rectangle, marking their outer edge.

2. Draw n black vertical lines on the canvas. The first line should be on the left edge of the patch, covering the left side of the border rectangle. The last line should be at the right edge, covering the right side of the border rectangle. All the other lines should be evenly spaced between the 2 sides. N is guaranteed to be at least 2.

When you run your quilt.py program from the command line, and the first arg is '-bars', main() calls your draw_bars() function, passing in whatever width/height/n numbers you typed on the command line.

The main() calls your draw_bars() function twice - once to draw bars in the upper left quadrant, and once to draw in the lower right quadrant (see below). This tests that your function works correctly for non-zero values of x,y.

Here is a command line run of the program to draw the bars patch, 300 pixels wide, 200 pixels hight, with n of 10:

$ python3 quilt.py -bars 300 200 10

alt: quilt 10 bars 300x200

The upper-left patch is drawn at x=0 y=0. The lower right patch is drawn, in this case, at x=300 and y=200.

Here is a run of the same size, but asking for 17 bars

$ python3 quilt.py -bars 300 200 17

alt: quilt 17 bars 300x200

And here is a run asking for 8 bars with patch size 200x200

$ python3 quilt.py -bars 200 200 8

alt: quilt 8 bars 200x200

b. draw_eye()

def draw_eye(canvas, x, y, width, height, n):

1. Draw the lightblue border rectangle, the same as for the bars.

2. Draw a yellow oval, with upper left at x,y and extending for width,height. The oval should just barely cover up the border rectangle on the four sides.

3. Draw N black lines starting from the center of the oval (// int division), extending to N points on the bottom edge, distributed evenly the same as for the bars.

The following command line calls your draw_eye(), 300 x 200, 10 lines:

$ python3 quilt.py -eye 300 200 10

alt: quilt eye 300x200 10 lines

c. draw_bowtie()

def draw_bowtie(canvas, x, y, width, height, n):

1. Draw the lightblue border rectangle as before.

2. Draw N red lines as follows. N will be 2 or more. The first line is from the upper left corner to the lower right corner of the patch. The next line moves down on the left, and up on the right. Continuing this pattern with the lines evenly spaced until the last line starts from the lower-left corner and goes to the upper right corner.

One approach: for each line 0, 1, 2, ... n-1, compute a "y_delta" amount which is the vertical distance from the start point. For the left side, the deltas move down from the upper left corner. For the right side, the deltas move up from the lower right corner.

To draw a line of a specific color, use the color= parameter like this: canvas.draw_line(0, 0, 10, 10, color='red')

The following command line runs draw_bowtie(), 300 x 200, 10 lines:

$ python3 quilt.py -bowtie 300 200 10

alt: quilt bowtie 300x200 10 lines

Milestone 3x Patches

Build and debug your code until it can draw all 3 patch types correctly for various sizes and values of N.

Quilting Bee

The last part uses decomposition to build the whole quilt. See the similar example in lecture.

The draw_quilt() function creates a canvas of the passed in width and height. The quilt will be made of an n-by-n grid of sub-rectangles, each the same size. We'll call the width and height of each sub-rectangle the sub_width and sub_height.

Compute the sub_width and sub_height for the quilt. For example if the overall canvas is 800 pixels wide and n is 11, the sub_width is 72, i.e. 800 divided by 11, rounding down is 72. Use the int division // operator.

Many times we have written a nested y/x loop to go over all the pixels in an image. In this case we want a nested loop over the row/col numbers of the patches, e.g. row=0 is the top row of patches, row=1 is the next row of patches and so on.

    # loop over rows and columns of patches
    for row in range(n):
        for col in range(n):
            # Draw one patch of the grid of patches

What is the x,y pixel coordinate of upper left corner of the patch at row,col? What is its width and height? What do you do to draw a patch there?

Milestone: Eye Test

Inside the row/col loop, call draw_eye() to draw an eye for every patch in the quilt to test that the row/col logic is working. Below is the command line to call your draw_quilt() function, here creating a 500 x 300 canvas with n of 5. That creates 5 x 5 patches, and each patch also uses n of 5 (we're using n for two things here - the number of patches, and the internal n of each patch).

$ python3 quilt.py -quilt 500 300 5

alt: quilt drawing 5 x 5 grid of eye

Patch Rotation

We want a scheme to draw a different patch type in every spot in the grid. There is a standard programming trick for this situation, where we want to cycle through patches like: bars, eye, bowtie, bars, eye, bowtie, bars, ...

Compute a choice int from the row and col numbers like this:

    choice = (row + col) % 3

The % modulo operator divides by 3 and returns the remainder. The result of % 3 is always one of 0, 1, 2, and in this case it will go in cycle like: 0, 1, 2, 0, 1, 2, 0, 1, 2, ...

So we can use choice to rotate between the different patch types. Change the inside of the row/col loop: if choice is 0, draw bars for that patch, if choice is 1, draw bowtie, and if choice is 2 draw eye. That is the deliverable state for your quilt program.

Here is the command line to run draw_quilt():

$ python3 quilt.py -quilt 600 400 6

alt: quilt 6 x 6 grid of patches

Here's a quilt with a relatively low value of n=3 giving it a more abstract look

$ python3 quilt.py -quilt 400 400 3

alt: quilt 3 x 3 grid of patches

As a final test, try a nice big quilt like

$ python3 quilt.py -quilt 1200 800 10

When all of the code is working, you should be able to draw a quilt with various sizes and various values of n. This program puts together loops, logic, and math, and leverages decomposition for sub-problems.

When your code is done and has clean style, please turn in your "quilt.py" file on Paperless which is linked from the CS106A home page.