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.

    Rectangle and Line

    Ellipse and Line

    Line

    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 of x 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 and b have on the drawings. Can you produce a blank drawing? Can you produce a drawing with only a line?

    Ellipse and Line

    No Drawing

    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 and b have on the drawings. Can you produce the same drawing variations as above? How do the tests for a and b 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);
        size(200, 200);
        for (int x = 20; x <= 180; x += 10) {
          line(x, 20, x, 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.

            int x = 0;
            while (x < 10) {
              println(x);
              x++;
            }

            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.

              int x = 10;
              do {
                println(x);
                x--;
              } while (x > 1)

              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:

                  // An example for loop
                  for (int x = 0; x < 10; x++) {
                    println(x);
                  }

                  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:

                  Large Squares

                  Small Squares

                  How would you modify the above sketch to produce the following drawing?

                  Diagonal Squares

                  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?

                  Triangular Squares

                  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 and y. As a challenge, see if you can reproduce the following examples with simple tests on x and y to the ones used above:

                  Experiment 1Experiment 2

                  Experiment with combining the values of x and y 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:

                  Experiment 3Experiment 4

                  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(); until endShape(CLOSE) and changing the values for the x-coordinates in all of the calls to the vertex() 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 the vertex() function (inside beginShape() and endShape()) by generating x and y coordinates.

                  Comments

                    Amy Cao about a year ago

                    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);

                    Chinmay Kulkarni about a year ago
                    • 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);
                    Last Updated: 14-Apr-2016 2:11 PM
                    Julia Spyrou about a year ago

                    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); } }

                    Matthew Brunker about a year ago

                    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 PM
                    Sarah Hearne about a year ago
                    • Show Sketch
                    /** @peep sketchcode */
                    size(390, 390); 
                     
                    //vertical
                    int x = 20; 
                    for (int y = 40; y < width; y += 60) {
                      rect(x-5, y-5, 30, 40);
                    }
                     
                    //horizontal
                    int y = 40; 
                    for (int x = 70; x < width; x += 60) { 
                      rect(x-5, y-5, 40, 30);
                    }
                    Yulong Guo about a year ago
                    • Show Sketch
                    /** @peep sketchcode */
                    background(random(255), random(255), random(255));
                    size(200, 200);
                    for(int y = 0; y <= 180; y += 20) {
                      for(int x = 0; x < y; x += 20) {
                        for(int a = 30; a >= 2; a -= 10) {
                          fill(random(255), random(255), random(255));
                        rect(x, y, a, a);
                      }
                    }
                    }
                     
                    for(int b = 0; b <= 180; b += 20) {
                      for(int c = 200; c > b; c -= 20) {
                        for(int d = 30; d >= 2; d -= 10) {
                          fill(random(255), random(255), random(255));
                          ellipse(c, b, d, d);
                        }
                      }
                    }
                    Last Updated: 17-Mar-2016 12:12 AM
                    Nathan Dagher about a year ago
                    • Show Sketch
                    /**@peep sketchcode */
                    size (400,400);
                    background(26, 0, 255);
                    //begin stripes
                    stroke (255);
                    for (int y = 390; y >= 390; y -= 20) {
                    for (int x = 10; x <= 390; x += 4) {
                      line(x, x, x, y);
                    }
                    }
                    //begin circles
                    noFill();
                    for (int d = 10; d < 390; d += 10) {
                      ellipse(d, d, d, d);
                    }
                    Last Updated: 23-Mar-2016 12:44 PM
                    Dale Harvey about a year ago

                    size (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