Tutorial 3: Drawing with Code

Drawing Points and Lines

Processing supports the drawing points, lines and a number of primitive shapes, i.e., triangles, quadrangles, rectangles, and ellipses. In addition, Processing supports the drawing of Bezier curves and more complex shapes as a series of vertices.

Drawing Points

Single points can be drawn to the display using the point() function. The point() function takes two parameters for the x and y co-ordinate of the point that we want to draw. Remembering that x-coordinates increase from left-to-right across the display window and that y-coordinates increase from top-to-bottom, i.e., (0, 0) is located in the top-left corner of the display window.

Coordinates in Processing

The colour used to draw the point is controlled by the stroke() function, which sets the colour used to 'stroke' lines and the outlines of shapes. Note that Processing uses the American spelling of colour, i.e., color, and that we'll use this when referring to them in the code.

  • Show Sketch
/** @peep sketchcode */
size(100, 100);
stroke(127, 0, 0);
point(20, 20);
point(25, 25);
point(30, 30);
point(35, 35);
 
stroke(0, 127, 0);
point(70, 50);
point(70, 55);
point(70, 60);
point(70, 65);

If you would like to experiment with any of the code in a tutorial, copy and paste the code into the editor window on the right-hand side of the page. For example, if you have problems seeing the points that are being drawn, copy the above code into the editor and add the following line before the first call to point():

We'll look at the strokeWeight() function a little later in this tutorial. but for now just run the sketch and observe what effect it has on the drawing.

Practice placing points on the screen to get used to the way that the x and y values are arranged in the window. Remember that the origin is in the top-left corner of the canvas and that the values for x and y increase as we travel right and down the screen. Try placing one point in each corner of the window, 10 pixels from the edge.

Drawing Lines

Individual lines can be drawn to the display using the line() function. The line() function takes 4 parameters for the x and y coordinates of the start and end points of the line. The following code draws 9 individual lines in three groups: the first group of three lines are red and horizontal (the y coordinate is the same for the start and end of each line), the second three are green and vertical (the x coordinate is the same for the start and end of each line), and the third group of three is blue and are not aligned with each other.

  • Show Sketch
/** @peep sketchcode */
size(100, 100);
stroke(127, 0, 0);
line(10, 30, 90, 30);
line(10, 40, 90, 40);
line(10, 50, 90, 50);
 
stroke(0, 127, 0);
line(40, 10, 40, 90);
line(50, 10, 50, 90);
line(60, 10, 60, 90);
 
stroke(0, 0, 127);
line(25, 90, 80, 60);
line(50, 12, 42, 90);
line(45, 30, 18, 36);

Practice drawing individual lines by writing a program that draws an 'X' to fill the display window, like this:

Crossed Lines

If you would like to practice some more with drawing lines, try writing sketches to create the following outputs:

Inset Cross

Boxed Cross

Diamond Cross

Drawing Shapes

Processing supports the drawing of simple shapes like triangles and quadrilaterals using the triangle() and quad() functions that take a list of parameters that specify the corners of the shape. Processing also supports the drawing of rectangles and ellipses. The meaning of the parameters given to the rect() and ellipse() drawing functions depends on the drawing mode currently being used.

Drawing Triangles

Triangles are drawn in Processing using the triangle() function, which takes a total of 6 parameters (when drawn in 2D). The 6 parameters describe 3 coordinate x-y pairs that describe the corners of the triangle. Here's the example from today's lecture slides:

  • Show Sketch
/** @peep sketchcode */
size(100, 100);
triangle(60, 10, 25, 60, 75, 65);
triangle(60, 20, 25, 70, 75, 75);
triangle(60, 30, 25, 80, 75, 85);

Continue practicing with the placement of coordinates in the display window by writing a sketch that can produce the following:

Triangles

Drawing Quadrilaterals

Quadrilaterals are any 4-sided shape. Drawing quadrilaterals in Processing is very similar to drawing triangles, we simply need to pass the quad() function the coordinate data for the shapes corner points. To draw in 2D this means supplying 8 numbers. Here's the example of drawing quadrilaterals that we saw in the lecture today:

  • Show Sketch
/** @peep sketchcode */
size(100, 100);
quad(60, 10, 25, 60, 60, 55, 75, 65);
quad(60, 20, 25, 70, 60, 65, 75, 75);
quad(60, 30, 25, 80, 60, 75, 75, 85);

Quadrilaterals allow relatively complex arrangements of 4 sided shapes to be arranged. Try writing a sketch that looks similar to the following:

Quadrilaterals

Drawing Rectangles

Rectangles are a type of quadrilateral, so we could use the quad() function to draw them, but they are so commonly needed that Processing includes a rect() function for drawing them. Drawing rectangles using the rect() function is a little different from the shape drawing functions we've seen so far, instead of specifying all of the corner points, which would typically require 8 numbers to be provided, the rect() function only requires 4 numbers. By default these 4 parameters specify the coordinate of the top-left corner of the rectangle and its width and height. (As we shall see in a moment, the way that the rect() function interprets the numbers it is given depends on the current rectangle drawing mode.) Here's the code from the lecture:

  • Show Sketch
/** @peep sketchcode */
size(100, 100);
rect(10, 10, 50, 50);
rect(20, 20, 50, 50);
rect(30, 30, 50, 50);
rect(40, 40, 50, 50);

There is no square() function in Processing, squares are simply drawn by passing the same width and height values to the rect() function.

Experiment with drawing with the rect() function by writing sketches that generate the following drawings:

Horizontal Rectangles

Vertical Rectangles

Offset Rectangles

Drawing Ellipses

Ellipses and circles are commonly required in many drawing applications but are difficult to draw quickly using straight lines. Processing provides the ellipse() function to handle this drawing task. Like the rect() function, ellipse() takes 4 parameters, by default the first two parameters specify the centre of the ellipse and the third and fourth parameters specify the diameter of the ellipse in the horizontal and vertical directions, i.e., the width and height of an unseen rectangle that bounds the ellipse. As with the drawing of squares, circles can be drawn by simply providing the same value for the width and height of the ellipse, as in this example:

  • Show Sketch
/** @peep sketchcode */
size(100, 100);
ellipse(35, 35, 50, 50);
ellipse(45, 45, 50, 50);
ellipse(55, 55, 50, 50);
ellipse(65, 65, 50, 50);

Drawing Curves

Curves (or splines) can be drawn in a number of different ways, Processing supports two varieties of curves Bezier and Catmull-Rom. The difference between these two methods of drawing curves is how the points provided are used interpreted.

Drawing Bezier Curves

Bezier curves are likely to be familiar if you have ever used a drawing program, especially a vector drawing program like Adobe Illustrator. A Bezier curve is constructed using four points; start and end points and two control points. The curve described by these points will be drawing from the start to the end point and will begin tangent to the line joining the start and first control point and will end tangent to the line joining the second control point and end point. The Bezier curve will not pass through the second and third control points.

The bezier() function draws a Bezier curve by taking 8 parameters (in 2D), or 4 pairs of coordinates. The first and last pairs of coordinates specify the start and end points of the curve, the middle two pairs specify the first and second control points.

Experiment with the following sketch to see what types of curves can be created with a single call to bezier(). You can drag the start, end and control points with the mouse.

  • Show Code
/** @peep sketch */
PVector[] points;
PVector draggingPoint;
 
void setup() {
  size(201, 201);
  points = new PVector[4];
  points[0] = new PVector(width/4, height/4);
  points[1] = new PVector(3*width/4, 2*height/4);
  points[2] = new PVector(2*width/4, 3*height/4);
  points[3] = new PVector(3*width/4, 3*height/4);
}
 
void draw() {
  background(204);
  smooth();
  noFill();
  stroke(0, 32);
  for (int x = 0; x < width; x += 10) line(x, 0, x, height);
  for (int y = 0; y < height; y += 10) line(0, y, width, y);
  stroke(0, 127);
  line(points[0].x, points[0].y, points[1].x, points[1].y);
  line(points[3].x, points[3].y, points[2].x, points[2].y);
  stroke(0);
  bezier(points[0].x, points[0].y,
         points[1].x, points[1].y,
         points[2].x, points[2].y,
         points[3].x, points[3].y);
  fill(255);
  ellipse(points[0].x, points[0].y, 4, 4);
  ellipse(points[3].x, points[3].y, 4, 4);
  fill(0);
  ellipse(points[1].x, points[1].y, 4, 4);
  ellipse(points[2].x, points[2].y, 4, 4);
}
 
void mousePressed() {
  float closestDist = 4;
  draggingPoint = null;
  for (int i = 0; i < points.length; i++) {
    float d = dist(mouseX, mouseY, points[i].x, points[i].y);
    if (d < closestDist) {
      closestDist = d;
      draggingPoint = points[i];
    }
  }
}
 
void mouseDragged() {
  if (draggingPoint == null) return;
  draggingPoint.x = mouseX;
  draggingPoint.y = mouseY;
}

The properties of Bezier curves makes it simple to smoothly join multiple curves together but difficult to draw a curve that must pass through a point that is not one of the start or end points of a curve.

BezierEllipse by Ira Greenberg

The following sketch is an example called "BezierEllipse" by Ira Greenberg that comes with the desktop version of Processing. The sketch shows the use of Bezier curves to produce a wide range of interesting shapes. (Don't worry about looking at the code for the moment, it uses techniques that we will explore in the coming weeks.)

  • Show Code
/** @peep sketch */
 
/**
 * Bezier Ellipse  
 * By Ira Greenberg 
 * 
 * Generates an ellipse using bezier() and
 * trig functions. Approximately every 1/2 
 * second a new ellipse is plotted using 
 * random values for control/anchor points.
 */
 
// arrays to hold ellipse coordinate data
float[] px, py, cx, cy, cx2, cy2;
 
// global variable-points in ellipse
int pts = 4;
 
color controlPtCol = #222222;
color anchorPtCol = #BBBBBB;
 
void setup(){
  size(200, 200);
  smooth();
  setEllipse(pts, 65, 65);
  frameRate(20);
}
 
void draw(){
  background(145);
  drawEllipse();
  if (frameCount % 20 == 0) {
    setEllipse(int(random(3, 12)), random(-100, 100), random(-100, 100));
  }
}
 
// draw ellipse with anchor/control points
void drawEllipse(){
  strokeWeight(1.125);
  stroke(255);
  noFill();
  // create ellipse
  for (int i=0; i<pts; i++){
    if (i==pts-1) {
      bezier(px[i], py[i], cx[i], cy[i], cx2[i], cy2[i],  px[0], py[0]);
    } else {
      bezier(px[i], py[i], cx[i], cy[i], cx2[i], cy2[i],  px[i+1], py[i+1]);
    }
  }
  if (drawControls) {
    strokeWeight(.75);
    stroke(0);
    rectMode(CENTER);
 
    // control handles and tangent lines
    for ( int i=0; i< pts; i++) {
      if (i==pts-1) {  // last loop iteration-close path
        line(px[0], py[0], cx2[i], cy2[i]);
      }
      if (i>0) {
        line(px[i], py[i], cx2[i-1], cy2[i-1]);
      }
      line(px[i], py[i], cx[i], cy[i]);
    }
 
    for ( int i=0; i< pts; i++){
      fill(controlPtCol);
      noStroke();
      //control handles
      ellipse(cx[i], cy[i], 4, 4);
      ellipse(cx2[i], cy2[i], 4, 4);
 
      fill(anchorPtCol);
      stroke(0);
      //anchor points
      rect(px[i], py[i], 5, 5);
    }
  }
}
 
// fill up arrays with ellipse coordinate data
void setEllipse(int points, float radius, float controlRadius){
  pts = points;
  px = new float[points];
  py = new float[points];
  cx = new float[points];
  cy = new float[points];
  cx2 = new float[points];
  cy2 = new float[points];
  float angle = 360.0/points;
  float controlAngle1 = angle/3.0;
  float controlAngle2 = controlAngle1*2.0;
  for ( int i=0; i<points; i++){
    px[i] = width/2+cos(radians(angle))*radius;
    py[i] = height/2+sin(radians(angle))*radius;
    cx[i] = width/2+cos(radians(angle+controlAngle1))* 
      controlRadius/cos(radians(controlAngle1));
    cy[i] = height/2+sin(radians(angle+controlAngle1))* 
      controlRadius/cos(radians(controlAngle1));
    cx2[i] = width/2+cos(radians(angle+controlAngle2))* 
      controlRadius/cos(radians(controlAngle1));
    cy2[i] = height/2+sin(radians(angle+controlAngle2))* 
      controlRadius/cos(radians(controlAngle1));
 
    //increment angle so trig functions keep chugging along
    angle+=360.0/points;
  }
}
 
boolean drawControls = false;
 
void keyPressed() {
  if (key == 'b' || key == 'B') {
    drawControls = !drawControls;
    redraw();
  }
}

The example has been modified here to allow the drawing of the control points to be turned on and off, to show the control points first click on the sketch and then press b on the keyboard.

Drawing Catmull-Rom Splines

The following editor allows you to experiment with Catmull-Rom curves by moving the position of four points that control the drawing of three curves. Notice that the curves drawn pass through each of the control points.

  • Show Code
/** @peep sketch */
PVector[] points;
PVector draggingPoint;
 
void setup() {
  size(201, 201);
  points = new PVector[4];
  points[0] = new PVector(width/4, height/4);
  points[1] = new PVector(3*width/4, 2*height/4);
  points[2] = new PVector(2*width/4, 3*height/4);
  points[3] = new PVector(3*width/4, 3*height/4);
}
 
void draw() {
  background(204);
  smooth();
  noFill();
  stroke(0, 32);
  for (int x = 0; x < width; x += 10) line(x, 0, x, height);
  for (int y = 0; y < height; y += 10) line(0, y, width, y);
  stroke(0);
  curve(points[0].x, points[0].y,
        points[0].x, points[0].y,
        points[1].x, points[1].y,
        points[2].x, points[2].y);
  curve(points[0].x, points[0].y,
        points[1].x, points[1].y,
        points[2].x, points[2].y,
        points[3].x, points[3].y);
  curve(points[1].x, points[1].y,
        points[2].x, points[2].y,
        points[3].x, points[3].y,
        points[3].x, points[3].y);
  fill(0);
  ellipse(points[0].x, points[0].y, 4, 4);
  ellipse(points[3].x, points[3].y, 4, 4);
  fill(255);
  ellipse(points[1].x, points[1].y, 4, 4);
  ellipse(points[2].x, points[2].y, 4, 4);
}
 
void mousePressed() {
  float closestDist = 4;
  draggingPoint = null;
  for (int i = 0; i < points.length; i++) {
    float d = dist(mouseX, mouseY, points[i].x, points[i].y);
    if (d < closestDist) {
      closestDist = d;
      draggingPoint = points[i];
    }
  }
}
 
void mouseDragged() {
  if (draggingPoint == null) return;
  draggingPoint.x = mouseX;
  draggingPoint.y = mouseY;
}

Tutorial Excerise

Your final exercise for this tutorial is to develop a sketch using the shape drawing functions that we've been looking at to draw a simple scene.

Write a portfolio post that documents your experiments developing a sketch. The dimensions of you sketch should be 400x400 pixels, i.e., use size(400, 400); to define the size of your sketch. To allow your sketch to run within the body text of your portfolio post, begin each sketch with:

  • Show Sketch
/** @peep sketchcode */
size(400, 400);

Comments

    Yanyi Feng about a year ago

    /** @peep sketchcode */ size(400, 400); stroke(153); background(255,435,10);

    ellipse(180,180,20,20); ellipse(180,160,20,20); ellipse(180,140,20,20); ellipse(180,120,20,20); ellipse(180,100,20,20); ellipse(180,80,20,20); ellipse(180,60,20,20); ellipse(180,40,20,20); ellipse(180,20,20,20);

    ellipse(160,20,20,20); ellipse(140,20,20,20); ellipse(120,20,20,20); ellipse(100,20,20,20); ellipse(80,20,20,20); ellipse(60,20,20,20); ellipse(40,20,20,20);

    ellipse(20,180,20,20); ellipse(20,160,20,20); ellipse(20,140,20,20); ellipse(20,120,20,20); ellipse(20,100,20,20); ellipse(20,80,20,20); ellipse(20,60,20,20); ellipse(20,40,20,20); ellipse(20,20,20,20);

    ellipse(40,180,20,20); ellipse(60,180,20,20); ellipse(80,180,20,20); ellipse(100,180,20,20); ellipse(120,180,20,20); ellipse(140,180,20,20); ellipse(160,180,20,20); ellipse(180,180,20,20);

    ellipse(100, 100, 55, 55);

    noStroke(); fill(20,120,50);

    fill(30,100,40);

    fill(10,90,30);

    ellipse(180,180,20,20); ellipse(180,160,20,20); ellipse(180,140,20,20); ellipse(180,120,20,20); ellipse(180,100,20,20); ellipse(180,80,20,20); ellipse(180,60,20,20); ellipse(180,40,20,20); ellipse(180,20,20,20);

    ellipse(160,20,20,20); ellipse(140,20,20,20); ellipse(120,20,20,20); ellipse(100,20,20,20); ellipse(80,20,20,20); ellipse(60,20,20,20); ellipse(40,20,20,20);

    ellipse(20,180,20,20); ellipse(20,160,20,20); ellipse(20,140,20,20); ellipse(20,120,20,20); ellipse(20,100,20,20); ellipse(20,80,20,20); ellipse(20,60,20,20); ellipse(20,40,20,20); ellipse(20,20,20,20);

    ellipse(40,180,20,20); ellipse(60,180,20,20); ellipse(80,180,20,20); ellipse(100,180,20,20); ellipse(120,180,20,20); ellipse(140,180,20,20); ellipse(160,180,20,20); ellipse(180,180,20,20);

    ellipse(100, 100, 55, 55);

    Last Updated: 9-Mar-2016 12:52 PM
    Natalia Gulbransen-Diaz about a year ago

    /** @peep sketchcode */ size(400,400); //Window size set at 400x400px background(255, 128, 0); //Background colour is orange

    // INITIAL RECTANGLE // Set the colour to fill shapes to white fill(255, 140, 26); //No stroke on the rectangle noStroke(); //Draw line from (50,50) to (160,160) rect (0,0,450,450);

    // SECONDARY RECTANGLE // Set the colour to fill shapes to white fill(255, 166, 77); //No stroke on the rectangle noStroke(); //Draw line from (50,50) to (160,160) rect (0,0,400,400);

    // TERTIARY RECTANGLE // Set the colour to fill shapes to white fill(255, 179, 102); //No stroke on the rectangle noStroke(); //Draw line from (50,50) to (160,160) rect (0,0,350,350);

    // FOURTH RECTANGLE // Set the colour to fill shapes to white fill(255, 191, 128); //No stroke on the rectangle noStroke(); //Draw line from (50,50) to (160,160) rect (0,0,300,300);

    // FIFTH RECTANGLE // Set the colour to fill shapes to white fill(255, 204, 153); //No stroke on the rectangle noStroke(); //Draw line from (50,50) to (160,160) rect (0,0,250,250);

    // SIXTH RECTANGLE // Set the colour to fill shapes to white fill(255, 217, 179); //No stroke on the rectangle noStroke(); //Draw line from (50,50) to (160,160) rect (0,0,200,200);

    // SEVENTH RECTANGLE // Set the colour to fill shapes to white fill(255, 230, 204); //No stroke on the rectangle noStroke(); //Draw line from (50,50) to (160,160) rect (0,0,150,150);

    // EIGTH RECTANGLE // Set the colour to fill shapes to white fill(255, 243, 230); //No stroke on the rectangle noStroke(); //Draw line from (50,50) to (160,160) rect (0,0,100,100);

    // NINTH RECTANGLE // Set the colour to fill shapes to white fill(255, 255, 255); //No stroke on the rectangle noStroke(); //Draw line from (50,50) to (160,160) rect (0,0,50,50);

    /* LINE BREAK - CIRCLES COMING UP */ //THIRTEENTH noStroke(); fill(255, 128, 0, 15); ellipse(450,450,1300,1300);

    //TWELFTH noStroke(); fill(255, 128, 0, 25); ellipse(450,450,1200,1200);

    //ELEVENTH noStroke(); fill(255, 128, 0, 35); ellipse(450,450,1100,1100);

    //TENTH noStroke(); fill(255, 128, 0, 45); ellipse(450,450,1000,1000);

    //NINTH noStroke(); fill(255, 128, 0, 55); ellipse(450,450,900,900);

    //EIGTH noStroke(); fill(255, 128, 0, 65); ellipse(450,450,800,800);

    //SEVENTH noStroke(); fill(255, 128, 0, 75); ellipse(450,450,700,700);

    //SIXTH noStroke(); fill(255, 128, 0, 85); ellipse(450,450,600,600);

    //FIFTH noStroke(); fill(255, 128, 0, 95); ellipse(450,450,500,500);

    //FOURTH noStroke(); fill(255, 128, 0, 105); ellipse(450,450,400,400);

    //THIRD noStroke(); fill(255, 128, 0, 115); ellipse(450,450,300,300);

    //SECOND noStroke(); fill(255, 128, 0, 125); ellipse(450,450,200,200);

    //FIRST noStroke(); fill(255, 128, 0,125); ellipse(450,450,100,100);

    /* LINE BREAK - FOLLOWING SECTION IS LINES */

    stroke(127, 0, 0); line(10, 30, 90, 30); line(10, 40, 90, 40); line(10, 50, 90, 50);

    stroke(0, 127, 0); line(40, 10, 40, 90); line(50, 10, 50, 90); line(60, 10, 60, 90);

    stroke(0, 0, 127); line(25, 90, 80, 60); line(50, 12, 42, 90); line(45, 30, 18, 36);

    /* LINE BREAK - FOLLOWING SECTION HAS TRIANGLES! */ fill(255); triangle(80, 100, 264, 300, 345, 200);

    Ian Thomas about a year ago

    size(400,400);

    int c;//declars variable 'c' - Center of canvas c = (200,200);//defines 'c' as (200,200), this is the center of the canvase

    stroke(127,0,0); strokeWeight(3); //the following are the 4 lines that form the square line(c-0,c-180,c-180,c+0) line(c-0,c-180,c+180,c+0) line(c-0,c+180,c-180,c+0) line(c-0,c+180,c+180,c+0) //the four lines that form the cross line(c-180,c-180,c+180,c+180) line(c+180,c-180,c-180,c+180)

    Ian Thomas about a year ago

    background(150); size(400,400);

    //declare variables 'l'(top left), 'c'(center), 'r'(bottom right) int c; c = (200,200); int l; l = (100,100); int r; r = (300,300);

    stroke(0); strokeWeight (5); point(c,c); point(l,l); point(r,r);

    triangle(c-40,c-0,l+0,l+60,l+0,l+140); triangle(c+40,c-0,r+0,r-60,r+0,r-140); triangle(c-0,c-40,l+60,l+0,l+140,l+0); triangle(c-0,c+40,r-60,r+0,r-140,r+0);

    Matthew Brunker about a year ago
    • Show Code
    • Show Sketch
    /** @peep sketch */
     
    /** @peep sketchcode */
     
    //this should be a triangle
    size(400, 400);
    fill(240, 60, 360);
    triangle(200, 40, 100, 280, 300, 280);
     
    //This should be an X that overlaps three triangles//
     
    stroke(127, 0, 0);//this is the stroke
    line(40, 120, 360, 280);//this is the line from the top left to the bottom right
    line(360, 120, 40, 280);//this is the line from the top right to the bottomr left
    line(40, 40, 320, 40);//this is the line on laying on top of the pillars
    line(40, 280, 360, 280);//this is the line on the bottom of the structure
     
    //These are parralel rectangles on both sides of the triangle
     
    fill(100, 160, 80);
    rect(40, 40, 40, 240);
    rect(320, 40, 40, 240);
     
    //This will be the quad diamond underneath
     
    fill(120, 120, 120);
    quad(200, 280, 360, 340, 200, 400, 40, 340);
    chris Huang about a year ago

    ~~~ size(200, 200) background(150, 200, 50) rect(10, 10, 50, 50); rect(20, 20, 50, 50); quad(60, 130, 125, 180, 60, 75, 75, 85);

    Brittany Klaassens about a year ago

    size(500, 500); background (200, 200, 200); //outside rectngle fill(160, 82 ,45); rect(100, 150, 300, 200); //inside rectangle fill(0, 0, 0); rect(125, 170, 250, 160); //buttons ellipse(113, 218, 12, 12); ellipse(113, 238, 12, 12); ellipse(113, 258, 12, 12); ellipse(113, 278, 12, 12); //antenna line(230, 150, 150, 30); line(230, 150, 290, 30); //table fill(188,143,143); rect(200, 350, 100, 40);