Tutorial 5: Drawing with Conditionals and Loops
Conditional Statements
Conditionals allow a program to make decisions about which lines of code to run. They let actions take place only when a specific condition is met. Conditionals allow a program to behave differently depending on the values of variables. For example, the program may draw a line or an ellipse depending on the value of a variable.
The if
structure is most commonly used in Processing to implement
conditionals:
if (test) {
statements
}
The test must be an expression that resolves to true
or false
.
When test evaluates to true, the statements inside the {
(left brace) and }
(right brace) are run. A sequence of statements between left and right braces
is called a block and is a common feature in Processing.
Drawing Variations with Conditionals
We can use conditionals, i.e, if
statements, to change what is drawn to the display based on the value of one or more variables. For example, the following sketch draws a different combination of an ellipse, a rectangle and a line depending on the value of the variable x
:
- Show Sketch
/** @peep sketchcode */
size(200, 200);
int x = 50;
if (x > 100) {
ellipse(100, 100, 72, 72);
}
if (x < 100) {
rect(70, 70, 60, 60);
}
line(40, 40, 160, 160);
Copy the above code and modify the value of
x
to produce the following drawings.
Extended Conditional Statements
To run some code when the result of a test is false
, use the else
keyword. The following code is similar to the code from the last sketch but uses the else
keyword to run the code that draws the rectangle when the test for x > 100
fails.
- Show Sketch
/** @peep sketchcode */
size(200, 200);
int x = 50;
if (x > 100) {
ellipse(100, 100, 72, 72);
} else {
rect(66, 66, 68, 68);
}
line(40, 40, 160, 160);
How is the above code different in behaviour from the first sketch in this tutorial? Can you produce all three of the drawing variations? If not, why?
Additionally, it is possible to add a condition to an else
block using else if(test)
. There can be many else if
blocks but only one else
block. The following code illustrates the use of an else if
block.
- Show Sketch
/** @peep sketchcode */
size(200, 200);
int x = 50;
if (x > 100) {
ellipse(100, 100, 72, 72);
} else if (x < 100) {
rect(66, 66, 68, 68);
} else {
line(40, 40, 160, 160);
}
Again, how is the above code different in behaviour from the above two sketches? What drawing variations are possible?
Embedded Conditional Statements
Conditional statements can be embedded inside other conditional statements. The following code shows how to embed a test for x < 300
inside another test for x > 100
. Notice that both tests have else
blocks to run alternative code if the test is false
.
- Show Sketch
/** @peep sketchcode */
size(200, 200);
int x = 50;
if (x > 100) {
if (x < 300) {
ellipse(100, 100, 72, 72);
} else {
line(40, 40, 160, 160);
}
} else {
rect(66, 66, 68, 68);
}
This sketch produces the same drawing variations as the previous one, but for different values of
x
. What is the smallest value ofx
is required to draw a line?
Combining Logical Tests
Logical operators combine Boolean values in different ways. The three most commonly used logical operators are OR, AND and NOT, these are written as ||
, &&
and !
in Processing code.
The Logical OR Operator
The logical OR operator combines Boolean values such that the result is true
if one (or both) of the Boolean values it is given are true
. Notice that this is different from the common use of the work "or" in English, where we mean that one or other of two statements is true but not both.
NOTE: This more common understanding of "or" is representing in Boolean logic is captured by the Exclusive-OR (XOR) operator, but we won't cover the use of that operator here because it is not commonly used.
The following code uses the logical OR operator to combine the values of tests on the variables a
and b
in different ways to produce drawing variations.
- Show Sketch
/** @peep sketchcode */
size(200, 200);
int a = 20;
int b = 20;
if ((a > 5) || (b < 30)) {
line(40, 100, 160, 100);
}
if ((a > 15) || (b < 30)) {
ellipse(100, 100, 72, 72);
}
Experiment with the above code to determine what values for
a
andb
have on the drawings. Can you produce a blank drawing? Can you produce a drawing with only a line?
The Logical AND Operator
The result of applying the logical AND operator is true
if (and only if) both of the values it is given are true
. Consequently, we can use the logical AND operator, written as &&
to test whether two tests are both true
.
- Show Sketch
/** @peep sketchcode */
size(200, 200);
int a = 20;
int b = 20;
if ((a > 5) && (b < 30)) {
line(40, 100, 160, 100);
}
if ((a > 15) && (b < 30)) {
ellipse(100, 100, 72, 72);
}
Experiment with the above code to determine what values for
a
andb
have on the drawings. Can you produce the same drawing variations as above? How do the tests fora
andb
change the values required to produce the drawing variations?
The Logical NOT Operator
The result of applying the logical NOT operator, written as !
in Processing, is false
if the value it is given is true
and vice versa. It can be particularly use for testing for the absence of something in a Processing sketch, especially when dealing with interaction, as we shall see later in this course, e.g., the following tests that the mouse button is not being pressed, if (!mousePressed) { ... }
.
- Show Sketch
/** @peep sketchcode */
size(200, 200);
int a = 20;
int b = 20;
if ((a > 5) && !(b < 30)) {
line(40, 100, 160, 100);
}
if (!(a > 15) && (b < 30)) {
ellipse(100, 100, 72, 72);
}
Compare the behaviour of the above sketch to the preceding one to see how the use of the NOT operator on two of the tests affects the drawing.
Repetition and Iteration
Iteration can be used to greatly reduced the amount of code required to accomplish repetitive tasks. Compare the following two pieces of code. They both draw the same pattern of vertical lines.
size(200, 200);
line(20, 20, 20, 180);
line(30, 20, 30, 180);
line(40, 20, 40, 180);
line(50, 20, 50, 180);
line(60, 20, 60, 180);
line(70, 20, 70, 180);
line(80, 20, 80, 180);
line(90, 20, 90, 180);
line(100, 20, 100, 180);
line(110, 20, 110, 180);
line(120, 20, 120, 180);
line(130, 20, 130, 180);
line(140, 20, 140, 180);
line(150, 20, 150, 180);
line(160, 20, 160, 180);
line(170, 20, 170, 180);
line(180, 20, 180, 180);
Iteration Using while
Loops
The while
structure is very much like the if structure, except that the statements inside the brackets are executed again and again until the test becomes false
.
while (test) {
statements
}
In the following example the statements inside the curly brackets will be executed as long as the value of x
is less than 10
. Notice that if the value of x
did not increase inside the while
loop, this loop would run forever.
Using do...while
Loops
A do...while
loop is similar to a while
loop, except that the test is
performed after the code inside the brackets is run. Consequently, the
code inside the brackets is always run at least once.
Iteration Using for
loops
Often we need to initialise, test and update a variable to complete a loop.
The for
structure allows these tasks to be put together and is structured
like this:
for (init; test; update) {
statements
}
The following example does the same as the example while loop we looked at earlier but using a for
loop:
Drawing Repeating Patterns with Loops
Loops allow us to write code that will be executed again and again until some test fails. Using a for
loop we can draw repetitive patterns. The following sketch illustrates how we can use a for
loop to produce a line of evenly spaced squares.
- Show Sketch
/** @peep sketchcode */
size(200, 200);
int y = 20;
for (int x = 20; x < width; x += 20) {
rect(x-5, y-5, 10, 10);
}
Modify the above code to produce a repetitive pattern with larger or smaller rectangles and different spacings between the rectangles. Like the following two examples:
How would you modify the above sketch to produce the following drawing?
Loops can also be used to repeat drawings that vary in ways other than by position, e.g., the following code varies the size of an ellipse to produce a series of rings:
- Show Code
/** @peep sketch */
size(200, 200);
noFill();
for (int d = 10; d < 100; d += 5) {
ellipse(100, 100, d, d);
}
Embedded Loops
By putting one for
loop inside another we can run a loop many times. Using embedded for
loops we can easily draw grid-like patterns:
- Show Sketch
/** @peep sketchcode */
size(200, 200);
for (int y = 20; y < height; y += 20) {
for (int x = 20; x < width; x += 20) {
rect(x-5, y-5, 10, 10);
}
}
Again, modify the above code to produce a repetitive pattern with larger or smaller rectangles and different spacings between the rectangles.
How can you modify the test of the inner loop for
x
to draw the following pattern?
Loops inside loops inside loops
We can continue embedding loops inside loops, for example the following sketch replaces the drawing of the rectangle above with the repeated ellipses from the preceding sketch to produce a complex interference pattern.
- Show Sketch
/** @peep sketchcode */
size(200, 200);
noFill();
stroke(0, 128);
for (int y = 20; y < height; y += 20) {
for (int x = 20; x < width; x += 20) {
for (int d = 10; d < 50; d += 5) {
ellipse(x, y, d, d);
}
}
}
Each time we add an inner loop we must remember that the number of times that the inner-most code is run will be the number of times each loop will be run multiplied together. So for the above example, the code drawing the ellipse is run 648 times. If we were to double the number of times the loops for x
and y
are run, the number of ellipses would increase to 2592, i.e., a factor of four.
Using Variables Inside Loops
Using and updating variables inside loops is an easy way to generate complex patterns based around grids. For example the following sketch uses the values for x
and y
to alter the shape as well as the position of the rectangles drawn:
- Show Sketch
/** @peep sketchcode */
size(200, 200);
for (int y = 20; y < height; y += 20) {
for (int x = 20; x < width; x += 20) {
rect(x-5, y-5, x/10, y/10);
}
}
By combining the values for x
and y
together to calculate the positions and shapes of ellipses, the results can become less grid-like.
- Show Sketch
/** @peep sketchcode */
size(200, 200);
fill(0, 76);
noStroke();
smooth();
for (int y = -width/10; y <= width; y += width/10) {
for (int x = -height/10; x <= height; x += height/10) {
float ex = x+y/8.0;
float ey = y+x/8.0;
float ew = 3*width/20 + x/2;
float eh = height/10;
ellipse(ex, ey, ew, eh);
}
}
Using Conditionals Inside Loops
Testing the value of variables inside loops using conditionals means that we can produce patterns that depend on different values, e.g., odd/even columns.
- Show Sketch
/** @peep sketchcode */
size(200, 200);
for (int y = 20; y <= height - 20; y += 10) {
for (int x = 20; x <= width - 20; x += 10) {
if ((x % 20) == 0) {
line(x, y, x+6, y-6);
} else {
line(x, y, x+6, y+6);
}
}
}
If we center the lines on the grid positions, we can create continuous patterns. For example, taking the above code and simply extending the lines either side of (x, y)
produces a regular wavy line:
- Show Sketch
/** @peep sketchcode */
size(200, 200);
for (int y = 20; y <= height - 20; y += 10) {
for (int x = 20; x <= width - 20; x += 10) {
if ((x % 20) == 0) {
line(x-5, y+5, x+5, y-5);
} else {
line(x-5, y-5, x+5, y+5);
}
}
}
We can quickly produce more complex patterns by combining together different logical operators used by the conditional test:
- Show Sketch
/** @peep sketchcode */
size(200, 200);
for (int y = 20; y <= height - 20; y += 10) {
for (int x = 20; x <= width - 20; x += 10) {
if ((x % 20) == 0 || (x % 50) == 0) {
line(x-5, y+5, x+5, y-5);
} else {
line(x-5, y-5, x+5, y+5);
}
}
}
We can also combine tests on x
and y
to produce interesting, and unexpectedly complex effects:
- Show Sketch
/** @peep sketchcode */
size(200, 200);
for (int y = 20; y <= height - 20; y += 10) {
for (int x = 20; x <= width - 20; x += 10) {
if ((x % 30) == 0 || (y % 50) == 0) {
line(x-5, y+5, x+5, y-5);
} else {
line(x-5, y-5, x+5, y+5);
}
}
}
Experiment with the above code to produce different effects using conditional statements based on the values of
x
andy
. As a challenge, see if you can reproduce the following examples with simple tests onx
andy
to the ones used above:
Experiment with combining the values of
x
andy
together using math operations before taking the modulus. The following sketches differ only in the way they combine x and y together, see if you can produce similarly complex patterns:
Creating Custom Shapes Using Loops
We can use loops to create complex custom shapes with vertices.
- Show Sketch
/** @peep sketchcode */
size(200, 200);
beginShape();
vertex(20, 20);
for (int y = 20; y <= 180; y += 10) {
if (y % 20 == 0) {
vertex(40, y);
} else {
vertex(80, y);
}
}
vertex(20, 180);
endShape(CLOSE);
Modify the above code to create a second sawtooth pattern as a mirror image of the existing one. Begin by copying the code from
beginShape();
untilendShape(CLOSE)
and changing the values for the x-coordinates in all of the calls to thevertex()
function.
We're not limited to using one loop inside beginShape()
and endShape()
, we can use as many as we need to generate the necessary vertices. For example, here is a version of the above that generates a double-sided sawtooth pattern:
- Show Sketch
/** @peep sketchcode */
size(200, 200);
beginShape();
for (int y = 20; y <= 180; y += 10) {
if (y % 20 == 0) {
vertex(80, y);
} else {
vertex(40, y);
}
}
for (int y = 180; y >= 20; y -= 10) {
if (y % 20 == 0) {
vertex(120, y);
} else {
vertex(160, y);
}
}
endShape(CLOSE);
Exercises
Create your own custom shape using a
for
loop and calls to thevertex()
function (insidebeginShape()
andendShape()
) by generating x and y coordinates.
Comments
stroke (245); int y = 20;
for (int x = 20; x < width; x += 20) { rect(x-5, x-5, 10, 10); }
fill (0);
size(200, 200); for (int y = 20; y < height; y += 20) { for (int x = 20; x < width; x += 20) { rect(x-5, y-5, x/10, y/10);
stroke (234); background(255);
int y = 20; for (int x = 20; x < width; x += 20) { rect(x-5, x-5, 10, 10); } fill (0); size(200, 200);
for (int y = 20; y < height; y += 20) { for (int x = 20; x < width; x += 20) { rect(x-5, y-5, x/20, x/20); } }
size(200, 200); for (int y = 20; y < height; y += 40) { for (int x = 20; x < width; x += 40) { rect(x-5, y-5, 10, 10); } }
size(200, 200); noFill(); stroke(0, 128); for (int y = 20; y < height; y += 40) { for (int x = 20; x < width; x += 40) { for (int d = 10; d < 50; d += 5) { ellipse(x, y, d, d); } } }
Last Updated: 16-Mar-2016 4:00 PMsize (200,200); // size of canvas int x=100; // number without a decimal place if (x>100) { ellipse (100,100,72,72); // draws ellipse if x is larger than 100 } if (x<100) { rect (70,70,60,60); // draws a rectangle if x is smaller than 100 } line(40,40,160,160); // draws a line regardless