Two things are going to happen in Lesson 2. First of all, we are going to read and discuss two papers (details on the next page) that give some insight into the inspiration for this course. Also, we are going to tackle the next level of programming in Processing. One thing that computers are very good at is repetitive tasks. That's why they were invented in the first place, to save time and increase accuracy when performing the same calculations over and over again. In this lesson we'll learn some basic syntax -- the for loop -- that will allow us to streamline repeated calculations.
By the end of this lesson, you should be able to write more complicated programs that involve modifying attributes of default shapes, drawing custom shapes, and performing repeated calculations.
This lesson will take us one week to complete. We will finish Lesson 2 on 1 June 2021.
If you have any questions, please post them to our Questions? discussion forum (not e-mail), located in Canvas. I will check that discussion forum daily to respond. While you are there, feel free to post your own responses if you, too, are able to help out a classmate.
This week we will read and discuss the two papers below. They are linked from the discussion in Canvas.
The first paper discusses the fact that successful geoscientists need to be adept at what cognitive scientists term "object visualization" and "spatial visualization." One of the challenges of designing successful learning materials for teaching geoscience concepts effectively is to recognize that these visualization skills are needed and to try to address them deliberately.
I think it is fair to say that K-12 science education is rather more focused on building vocabularic and conceptual knowledge (i.e. "List the three types of plate boundaries") rather than honing the skills used by scientists, such as the visualization skills brought up in this paper. One of my goals for this course is to explore and teach visualization skills through the medium of computer programming, so keep that in mind when you read the first paper.
The second paper is by a team of neuroscientists and my take-away from it is that even in adulthood, learning a new skill changes your brain for the better. That discovery addresses my second goal for this course which is to teach you a new skill set that will hopefully be useful to you. Even if it is not directly useful, my intent is that the learning process will be beneficial in and of itself.
As you read, consider the following questions, which we will discuss as a class:
Once you have finished the readings, engage in a class discussion that will take place over the entire week devoted to Lesson 2. For specific dates, consult the lesson overview page. This discussion will require you to participate multiple times over that period.
You will be graded on the quality of your participation. See the grading rubric [1] for specifics.
The default for a rectangle is for its origin to be at the top left corner, and the default for an ellipse is for its origin to be at its center. You can change these defaults by resetting rectMode() and ellipseMode(). For example, if you specify rectMode(CENTER), then the four arguments taken by rect() become the (x,y) coordinate of its center and then the half-width, and half-height, respectively. To revert back to the default, specify rectMode(CORNER). Read about more options at Processing's command reference page for rectMode() [2]. If you specify ellipseMode(CORNER), then the four arguments taken by ellipse() become the (x,y) coordinate of the upper left corner of a rectangle that circumscribes the ellipse. Then the other two arguments are the width and length of that bounding rectangle. Read about more options at Processing's command reference page for ellipseMode() [3].
It is my personal preference not to change these defaults. I find it easier to construct my mental map of where I want to place shapes in a composition working within the framework specified by the defaults. However, there isn't a right or wrong approach, in my opinion. See the code below for a sample of code and its corresponding display window that demonstrate what happens when rectMode() and ellipseMode() are changed.
size ( 200 , 200 ); //demonstrate rectMode rectMode ( CENTER ); rect ( 35 , 35 , 50 , 50 ); rectMode ( CORNER ); fill ( 102 ); rect ( 35 , 35 , 50 , 50 ); // demonstrate ellipseMode // demonstrate noFill ellipseMode ( CENTER ); fill ( 0 ); ellipse ( 135 , 135 , 50 , 50 ); ellipseMode ( CORNER ); fill ( 102 ); ellipse ( 135 , 135 , 50 , 50 ); ellipseMode ( CENTER ); noFill (); ellipse ( 150 , 150 , 100 , 100 ); |
My compositions are more fun if they include color. The default way to specify the color of things in Processing is with (r,g,b) values. This is red, green, and blue. Remember how if you got really close to an old picture-tube television set, you could see the red, green, and blue lights in different arrangements that made up the whole picture? Same basic idea. These colors are the opposite of paint in that if you add the full amount of each one you get white, not black (or really a muddy brown if you use actual paint). You can also specify the color by its hue, saturation, and brightness (h,s,b) or in hexadecimal. To switch to hsb from the rgb default, you have to use colorMode(HSB). If you want to use hexadecimal, just use the appropriate value (which you can find in the Tools menu or probably by googling).
I usually just use rgb values, so the rest of this discussion assumes rgb. Each value of red, green, and blue can range from 0 to 255. Trial and error is certainly one way to come up with a pleasing color palette, but a better way is to use the color selector in Processing. Go to the Tools menu and select "Color Selector" from the drop-down menu. See figure below for a snapshot of the Color Selector. Once this is open, you can play around to find the color you want. The numbers corresponding to that color are given, and you can just type them into your program in the appropriate place.
Any function that took an argument to define its greyscale can be a color instead. This includes stroke(), fill(), and background(). You can also vary how transparent or opaque objects look by changing the alpha value. This is an optional fourth argument to specifying color. It also ranges from 0 (totally transparent) to 255 (completely opaque). Completely opaque is the default so by not specifying a fourth number you will just get completely opaque colors.
Demo about adding color.
Processing has intrinsic functions to draw several shapes besides points, lines, ellipses and rectangles. I'm just going to list several of them here along with a link to each of their reference pages on Processing's website. My goal in this tutorial is not to write a textbook. Anyway, there are several good ones already out there that I already told you about, so you should read the appropriate sections of those if you want more information about any of these:
But what if you want to draw your own shape? Like, say, how about the lightning bolt on Roy Hobbs' bat that later became a patch on the whole team's uniform in The Natural? I've found a way to work a baseball reference into all my other courses, so why not? In case you don't know what I'm talking about, this is it:
Your friends for this task are beginShape(), endShape(), and vertex(). What you do is use a beginShape() endShape() pair to surround a list of vertex() commands to draw the outline of your shape point by point. Processing will connect up a series of vertices with straight lines. If your last command is endShape(CLOSE) then Processing with connect up the last point with the first point so you can make a closed shape without having to specify the first point again. On the other hand, if you don't want that, then just do endShape(). Here's my lightning bolt along with the program that draws it as a yellow lightning bolt on a black background.
size ( 100 , 200 ); background ( 0 ); noStroke (); pixelDensity( 2 ); fill ( 250 , 230 , 5 ); beginShape (); vertex ( 20 , 10 ); vertex ( 20 , 60 ); vertex ( 30 , 50 ); vertex ( 20 , 110 ); vertex ( 30 , 100 ); vertex ( 20 , 170 ); vertex ( 60 , 75 ); vertex ( 50 , 85 ); vertex ( 60 , 35 ); vertex ( 50 , 45 ); vertex ( 60 , 10 ); endShape ( CLOSE ); |
Notice in the program above there are two commands that we haven't specifically covered yet. They are pixelDensity() and noStroke().If you have a big-definition display screen on your computer, such as Apple's Retina display or Windows' High-DPI display, then using pixelDensity(2) allows your computer to use all its pixels when it renders one of your drawings. Add it in and then take it out and you'll be able to see the difference in how shapes are rendered on your screen. The noStroke() function tells Processing not to draw an outline around your shape.
2.1 Create a composition out of two or more differently colored overlapping shapes
2.2 Modify Exercise 2.1 above to change the color and thickness of the outlines of the shapes and the background color of the composition.
2.3 Create your own custom shape with vertex(), beginShape(), and endShape().
You don't have to turn in 2.1, 2.2, or 2.3. As before, I recommend working through all the exercises anyway, even the ones that you are not required to turn in.
When you were drawing your own shapes with vertex(), you probably did what I did and used trial and error to place each vertex until you got the shape to look the way you wanted it to. Or maybe you thought ahead and drew it on graph paper first. Now let's say you like that shape but you wish it was in a slightly different place in the display window. Ugh! What a pain! You'll have to go back and recalculate every vertex. (This is true even if you used graph paper. bummer!) I don't want to do this, and I'll probably mess up somewhere along the way. Ah, but if you use variables then you can solve the annoying recalculation problem!
Here's the same lightning bolt as I drew before, but now I'm going to define two variables to use as the origin. Every subsequent vertex will be written relative to that origin. For example, in the original program the first vertex was vertex(20,10). This time around I'm going to declare an integer variable named x and assign it the value of 20. I'm also going to declare another integer variable called y and assign it the value of 10.
Now that x = 20 and y =10, I can tell Processing to do vertex(x,y) instead. The second vertex was vertex(20,60). I want to write this in terms of x and y so I write vertex(x,y+50). I go through all the vertices in the shape, and with some simple mental arithmetic I transform each one into an equivalent value using x and y. Below is the lightning bolt program in which the vertices are set by variables.
size ( 100 , 200 ); background ( 0 ); noStroke (); fill ( 250 , 230 , 5 ); int x = 20 ; int y = 10 ; beginShape (); vertex (x, y); vertex (x, y + 50 ); vertex (x + 10 , y + 40 ); vertex (x, y + 100 ); vertex (x + 10 , y + 90 ); vertex (x, y + 160 ); vertex (x + 40 , y + 65 ); vertex (x + 30 , y + 75 ); vertex (x + 40 , y + 25 ); vertex (x + 30 , y + 35 ); vertex (x + 40 , y); endShape ( CLOSE ); |
Up near the beginning of the program I declared two variables and I named them "x" and "y." I gave them those names because it makes intuitive sense to me to think of horizontal positions as x values and vertical positions as y values. However, I could have named those variables anything I wanted and still used them as x and y values. I could have called them "duck" and "goose" or whatever. I could even have used "y" for horizontal and "x" for vertical (although I think this choice would confuse me a lot later -- not the best idea). In the function vertex(), the first value specified is always the horizontal position and the second value specified is always the vertical position. It does not matter what those values are named.
I will now amend the statement, "it doesn't matter what they are named," to tell you that actually there are a few rules about naming variables in Processing. The names can't start with a number and can't have spaces in them. It is also a really really good idea not to give a variable a name that Processing already uses for something else. There's a list of Processing variables at their website.
variable | okay? | comments |
---|---|---|
x | yes | |
1x | no | can't start with a number |
x1 | yes | |
x 1 | no | can't have a space inside a variable name |
x_1 | yes | an underscore is okay when you really want a space |
x_direction | yes | you can write a whole word -- makes it more readable |
xDirection | yes | some people capitalize subsequent words instead of using an underscore. This is called "camel case" |
fill | no | don't use a name that Processing already uses |
When I defined the two variables, "x" and "y" up at the top of the program, I didn't just write x = 20. I wrote int x = 20. That tells Processing that I want to make an integer variable and name it x and I am assigning the value 20 to x. An integer means a whole number with no fractional parts. 3 is an integer, -3 is an integer, 0 is an integer, but 3.5 is not an integer. You can declare a variable and assign a value to it in more than one step and some people prefer this for clarity. For example
int x; x = 20 ; |
is equivalent to
int x = 20 ; |
And,
int x, y; x = 20 ; y = 10 ; |
is equivalent to
int x = 20 ; int y = 10 ; |
You will have to experiment with the syntax that makes the most sense to you. There are other types of variables besides integers and we will get to them later on. Now back to the program.
Upon first glance it doesn't really look like we have saved ourselves any effort here compared to writing it where we named every vertex position explicitly. After all, we have typed a lot more characters by declaring variables, haven't we? Plus we had to do some addition and subtraction in our head to rewrite the position of each vertex. But let's say I want to scooch the whole lightning bolt over and down little bit so it's more centered in the display window. That is easy-peasy lemon-squeezy as my first grader says. All I have to do is change the values of x and y and recalculate nothing else at all. Let's do it. Instead of making x = 20 and y = 10, we'll make x = 30 and y = 20. The code for the new lightning bolt program after having changed the x and y assignments to 30 and 20 is below.
size ( 100 , 200 ); background ( 0 ); noStroke (); fill ( 250 , 230 , 5 ); int x = 30 ; int y = 20 ; beginShape (); vertex (x, y); vertex (x, y + 50 ); vertex (x + 10 , y + 40 ); vertex (x, y + 100 ); vertex (x + 10 , y + 90 ); vertex (x, y + 160 ); vertex (x + 40 , y + 65 ); vertex (x + 30 , y + 75 ); vertex (x + 40 , y + 25 ); vertex (x + 30 , y + 35 ); vertex (x + 40 , y); endShape ( CLOSE ); |
There. I like the way that looks better.
While you are at it, is the "Quiz yourself" exercise above building your spatial visualization skills or object visualization skills, or both, or neither?
2.4 Draw your own custom shape using variables to set the vertices.
You don't have to turn in Exercise 2.4, but you should work through it anyway.
Let's say it's a thunderstorm and we want to draw a whole bunch of our stylish lightning bolts to the screen. Luckily computers were built precisely to make repetitive calculations quickly. One way to take advantage of a computer's ability to do this is with a for loop. Check out the program below.
// use a for loop to draw several lightning bolts size ( 400 , 200 ); background ( 0 ); noStroke (); smooth (); fill ( 250 , 230 , 5 ); int y = 20 ; for ( int i = 0 ; i < 400 ; i = i + 40 ) { beginShape (); vertex (i, y); vertex (i, y + 50 ); vertex (i + 10 , y + 40 ); vertex (i, y + 100 ); vertex (i + 10 , y + 90 ); vertex (i, y + 160 ); vertex (i + 40 , y + 65 ); vertex (i + 30 , y + 75 ); vertex (i + 40 , y + 25 ); vertex (i + 30 , y + 35 ); vertex (i + 40 , y); endShape ( CLOSE ); } |
The major new thing in this program is the section that goes:
for ( int i = 0 ; i < 400 ; i = i + 40 ) { ...some commands } |
The line begins with the command for and then inside the parentheses are three parts, separated by semicolons.
The part that says int i = 0; initializes the variable to loop over. In our program we are naming that variable i and setting it equal to zero.
The next part that says i < 400; is a test. If the test is true, all the commands inside the curly braces are executed one at a time in order using the value of the loop variable wherever that variable appears. If the test fails, Processing ignores all the commands inside the curly braces and moves along to the rest of the program. In our program that test checks to see whether the value of the loop variable is less than 400 or not.
The third part that says i = i + 40 is the increment. When the for loop finishes the first time using the initial value of the loop variable, it goes back to the top of the for loop, increments the loop variable by the amount indicated (it adds 40 in this program), then it reassigns the variable to the new value. It checks if the test is still true, and if it is, it executes all the commands inside the curly braces with the new value of the loop variable. It repeats incrementing and executing until the test fails, and then it moves on and doesn't try to execute the for loop any more times.
So put it all together and here is what this for loop does. It starts out with i = 0; It runs all the commands inside the curly braces using 0 every time it sees an "i." Then it adds 40, checks whether 40 is less than 400. It is, so it runs all the commands inside the curly braces using 40 every time it sees an "i". Then it adds 40, checks whether 80 is less than 400. It is, so it runs all the commands inside the curly braces using 80 every time it sees an "i." This goes on until i gets to 400 or higher. When that happens, Processing skips all the commands inside the curly braces and moves on to see if there are any commands to run after the curly braces.
What all this accomplishes is to draw the lightning bolt over and over again, each time moving it 40 pixels to the right. See how much trouble we have saved by writing a loop rather than writing multiple beginShape/endShape chunks!
The initial variable can be a negative, zero, or positive. You can declare the variable before the for loop starts. The test can involve any relational operator, which is a fancy way of saying anything that compares two values. We will learn more about relational operators later but here are the most common ones:
The increment can be anything you want and it can be positive or negative.
Here's what it looks like when you write two for loops and the only difference between them is the initialization variable:
// for loop to demonstrate changing the initialization size ( 400 , 100 ); pixelDensity( 2 ); //makes prettier circles on a retina display int y = 20 ; //set the vertical position //this for loop makes a row of evenly-spaced circles for ( int i = 0 ; i< 400 ; i=i+ 50 ){ ellipse (i,y, 20 , 20 ); } y= 40 ; //shift the vertical position down //this for loop makes the same row of circles but shifted over //by 10 pixels because we changed the initialization variable for ( int i= 10 ; i< 400 ; i=i+ 50 ){ ellipse (i,y, 20 , 20 ); } |
The top line of circles were placed by starting at a horizontal position of zero, and a vertical position of 20. Then the horizontal position in increased by 50 and the vertical position is unchanged, and another same-sized circle is drawn. Then the horizontal position is increased by 50 more, the vertical position is unchanged, and another same-sized circle is drawn. This goes on until we reach a horizontal position of 400.
The loop says:
for ( int i = 0 ; i< 400 ; i=i+ 50 ){ ellipse (i, 20 , 20 , 20 ); } |
That first loop is the equivalent of:
ellipse ( 0 , 20 , 20 , 20 ) ellipse ( 50 , 20 , 20 , 20 ); ellipse ( 100 , 20 , 20 , 20 ); ellipse ( 150 , 20 , 20 , 20 ); ellipse ( 200 , 20 , 20 , 20 ); ellipse ( 250 , 20 , 20 , 20 ); ellipse ( 300 , 20 , 20 , 20 ); ellipse ( 350 , 20 , 20 , 20 ); |
See how much typing you save with a loop, and also the chance of making an error is less because the computer is doing the computation for you.
The second loop in the program only differs from the first one in the initialization variable (and we shifted the vertical position down so we could see both sets of circles more easily). The second loop says:
for ( int i = 10 ; i< 400 ; i=i+ 50 ){ ellipse (i, 40 , 20 , 20 ); } |
That second loop is the equivalent of:
ellipse ( 10 , 40 , 20 , 20 ) ellipse ( 60 , 40 , 20 , 20 ); ellipse ( 110 , 40 , 20 , 20 ); ellipse ( 160 , 40 , 20 , 20 ); ellipse ( 210 , 40 , 20 , 20 ); ellipse ( 260 , 40 , 20 , 20 ); ellipse ( 310 , 40 , 20 , 20 ); ellipse ( 360 , 40 , 20 , 20 ); |
Again, this would be a long program if we had set each of these circles by hand. Rule of thumb: If you find yourself typing a few commands in a row that look very repetitive, then a loop is probably a good idea. Note that when you are constructing a program, sometimes you don't start out realizing you want a loop until you notice that you've just typed a bunch of repetitive commands.
Here's what for loops look like when the only difference between them is the test.
// for loop to demonstrate negative increments size ( 400 , 150 ); pixelDensity( 2 ); //makes prettier circles on a retina display int y = 20 ; //set the vertical position //this for loop makes a row of evenly-spaced circles for ( int i = 0 ; i< 200 ; i=i+ 50 ){ ellipse (i,y, 20 , 20 ); } y= 40 ; //shift the vertical position down //this for loop makes a row of circles but ends in a different place for ( int i= 0 ; i<= 200 ; i=i+ 50 ){ ellipse (i,y, 20 , 20 ); } y= 60 ; //shift the vertical position down some more //this for loop makes a row of circles but ends in a different place for ( int i= 0 ; i<= 300 ; i=i+ 50 ){ ellipse (i,y, 20 , 20 ); } y= 80 ; //shift the vertical position down some more //what if the initialization and test are the same for ( int i= 0 ; i<= 0 ; i=i+ 50 ){ ellipse (i,y, 20 , 20 ); } y= 100 ; //shift the vertical position down some more //won't plot any circles because the test immediately fails for ( int i= 0 ; i< 0 ; i=i+ 50 ){ ellipse (i,y, 20 , 20 ); } |
The program above has 5 loops. The first one draws four circles, with origins at (0,20), (50,20), (100,20), and (150,20). It does not draw a circle at x = 200 because the test says to execute the loop only in cases where the increment variable is less than 200. The second loop does draw a circle at (200,40) because the the test says to execute the loop in cases where the increment variable is less than or equal to 200. The third loop draws a couple more circles because the test says to execute up to and including 300. The fourth loop has the initialization variable exactly equal to the test, so the loop executes once and then stops. (No need to write a loop in this case, and the increment doesn't even matter here. It's just for demonstration purposes.)
The 5th loop doesn't plot anything because the initialization variable fails the test right off the bat. So the loop doesn't execute at all. Note that Processing won't give you an error message in a case like this one because nothing you wrote has incorrect syntax. Writing a relational test that always fails is a mental error, but not officially a programming error, so just keep that in mind when troubleshooting your code when you get unexpected results.
Here's an example of what happens when you change the increment variable from one loop to another, but leave the rest alone.
// for loop to demonstrate changing the increment size ( 400 , 100 ); pixelDensity( 2 ); //makes prettier circles on a retina display int y = 20 ; //set the vertical position //this for loop makes a row of evenly-spaced circles for ( int i = 0 ; i< 400 ; i=i+ 50 ){ ellipse (i,y, 20 , 20 ); } y= 40 ; //shift the vertical position down //this for loop makes a row of circles with less space between them //because we changed the initialization variable for ( int i= 0 ; i< 400 ; i=i+ 30 ){ ellipse (i,y, 20 , 20 ); } |
The only difference between the two loops is that I made the increment smaller in the second one. This results in more circles, spaced closer together. If I had made the increment bigger, there would be fewer circles spaced farther apart.
You can start at some initial value and work backwards to a lower value, as in the program below.
// for loop to demonstrate negative increments size ( 400 , 100 ); pixelDensity( 2 ); //makes prettier circles on a retina display int y = 20 ; //set the vertical position //this for loop makes a row of evenly-spaced circles //starting in the middle and going to the right for ( int i = 200 ; i< 400 ; i=i+ 50 ){ ellipse (i,y, 20 , 20 ); } y= 40 ; //shift the vertical position down //this for loop makes a row of circles //starting in the middle and moving to the left for ( int i= 200 ; i> 0 ; i=i- 50 ){ ellipse (i,y, 20 , 20 ); } |
In the first loop, we start at (200,20), and make evenly-spaced circles that shift to right by 50 pixels, until we get to x=400, then we stop. So the first loop is the equivalent of:
ellipse ( 200 , 20 , 20 , 20 ); ellipse ( 250 , 20 , 20 , 20 ); ellipse ( 300 , 20 , 20 , 20 ); ellipse ( 350 , 20 , 20 , 20 ); |
In the second loop, we start at (200,40), and make evenly-spaced circles that shift to the left by 50 pixels each time until we get to x=0. Note that not only do we have to change the increment, but we have to change the test portion of the loop as well in order to make this work. The second loop is the equivalent of:
ellipse ( 200 , 40 , 20 , 20 ); ellipse ( 150 , 40 , 20 , 20 ); ellipse ( 100 , 40 , 20 , 20 ); ellipse ( 50 , 40 , 20 , 20 ); |
When you set up a for loop pay attention so that you don't write a loop that will never terminate. For example, what if I wrote the following loop:
for (int i = 10; i < 200; i = i - 10) |
Bad trouble! Why? The initial value of i is 10, and then I am decreasing the value of i by 10 in the increment portion. But, my test checks whether or not the value of i is less than 200 and if it is, to go ahead and execute the loop. The value of i will never exceed 200 since i is getting more negative all the time, so this loop will never end because the test will never fail.
You can write for loops inside of other for loops. I think of this kind of thing kind of like tiling a cookie tray with the dough for a batch of cookies. Let's say you've made enough dough for 1 dozen cookies and you have a cookie tray. Here's a way to think of a pair of nested loops that explains how to put the dough blobs on the tray into 4 columns of 3 blobs each. (I think following along with my written description is a spatial visualization exercise, what do you think?)You go to first position in the upper left corner of the tray, then you execute a loop 3 times so that at the end of the loop, you have put 3 dough blobs on the tray in a column. That loop finishes and then you move one position to the right. You execute the same loop three more times so that you make a new column of dough blobs next to the first column. Keep going until you've got four columns with three cookies in each column. Here's how you'd write in Processing what I just explained in English.
int doughBlobSize = 20 ; for ( int xpos = 10 ; xpos < 100 ; xpos = xpos + 25 ) { for ( int ypos = 10 ; ypos < 100 ; ypos = ypos + 40 ) { println ( "xpos =" + xpos, "ypos =" + ypos); ellipse (xpos, ypos, doughBlobSize, doughBlobSize); } } |
I put the println() command in there so that when the program runs, you can check that the loops are doing what you thought they were doing. In general, sticking a println() command into your code somewhere is a good idea when you get unexpected output or an error and you want to double check that variables have the values you thought they did.
Let me break down the syntax println("xpos =" + xpos, "ypos =" + ypos);
The part that goes "xpos =" says to print the string xpos =
The part that goes + xpos says to print the value assigned to the variable named xpos
The comma tells Processing to put in a white space
The part that goes "ypos =" says to print the string ypos =
The part that goes + ypos says to print the value assigned to the variable named ypos
The commands are executed very fast but that println command gets executed 12 times, and each time the value of xpos and ypos have changed so it prints the new value to the screen. If you look at all the values in the console and cross-check that information with the display window output, you should be able to see the order in which the position of each dough blob was determined, even though they all get plotted at once in the blink of a human eye.
A screenshot of the program and its output:
A program demonstrating a nested for loop. Click for text.
size ( 200 , 200 ); stroke ( 255 ); line ( 10 , 0 , 10 , 100 ); stroke ( 0 ); for ( int i = 10 ; i < 200 ; i = i + 10 ) { println (i); fill (i); ellipse (i, i, 10 , 10 ); } stroke ( 255 ); line ( 30 , 0 , 30 , 100 ); |
This program first draws a white vertical line, then it starts a loop in which it draws a diagonal series of circles, each one lighter in color that the last. Then it leaves the loop and draws another vertical white line. This program demonstrates loops and command order. You can tell that the first white line was set before the loop started because the circles plot on top of it. The second white line came after the loop because it is drawn on top of the circles. The circles go in a diagonal line instead of tiled because I am incrementing both x and y at the same time instead of nesting one loop inside another loop.
2.5 Rewrite the dough blob program so that you place the blobs in the same configuration, but you start from the bottom right corner and work upwards and to the left.
2.6 Use at least one for loop to draw your custom shape from Exercise 2.4 several times.
Turn in Exercise 2.6 to the Lesson 2 dropbox by the due date indicated on this lesson's overview page. Here's what I am looking for in your program: correct use of beginShape(), endShape(), and vertex(), use of variables to set the vertices, and correct use of a for loop to draw the shape multiple times. Name your file lastname2_6.pde
You have reached the end of Lesson 2! In this lesson you learned about variables and for loops, and a little bit about how to troubleshoot a loop with the println command. These will all be useful building blocks for the more complicated programs we'll learn in Lesson 3.
Double-check the to-do list on the Lesson 2 Overview page to make sure you have completed all of the activities listed there before you begin Lesson 3.
2.1 Create a composition out of two or more differently colored overlapping shapes
2.2 Modify Exercise 2.1 above to change the color and thickness of the outlines of the shapes and the background color of the composition.
2.3 Create your own custom shape with vertex(), beginShape(), and endShape().
2.4 Draw your own custom shape using variables to set the vertices.
2.5 Rewrite the dough blob program so that you place the blobs in the same configuration, but you start from the bottom right corner and work upwards and to the left.
2.6 Use at least one for loop to draw your custom shape from Exercise 2.4 several times. [Turn this one in]
Links
[1] https://www.e-education.psu.edu/earth801/node/537
[2] http://processing.org/reference/rectMode_.html
[3] http://processing.org/reference/ellipseMode_.html
[4] http://processing.org/reference/arc_.html
[5] http://processing.org/reference/bezier_.html
[6] http://processing.org/reference/triangle_.html
[7] http://processing.org/reference/curve_.html
[8] http://www.yesteryearsports.com/New-York-Knights-1939-Home-Jersey-Roy-Hobbs-NYK39H.htm
[9] https://www.e-education.psu.edu/earth801/sites/www.e-education.psu.edu.earth801/files/screencasts/forLoop.mp4
[10] https://www.e-education.psu.edu/earth801/sites/www.e-education.psu.edu.earth801/files/screencasts/forLoopCC.mov