37. Samples

This page shows a number of programs that we discussed in class

37.1. HSB Color Mode

Moving the mouse down the window displays all the colors in the color wheel:

void setup(){
   size(500,500);
}

void draw(){
  // Map mouse Y coordinate to color on color wheel
  float hue = map(mouseY, 0, 499, 0, 360);
  colorMode(HSB, 360, 100, 100); // HSB mode

  // Set stroke color and weight
  stroke(hue, 100, 100);
  strokeWeight(10);
  // Draw horizontal line across window
  line(0, mouseY, 499, mouseY);
}

37.2. Functions - Eyes

Shows the use of functions to repeatedly draw some shapes:

void setup(){
  size(500,500);
  noStroke();
}

void draw(){
  eye(65, 44);
  eye(20, 50);
  eye2(325, 220, 180);
  eye2(190, 202, 180);
  threeXs();
}

// Draws an eyeball at x, y
void eye(int x, int y){
  fill(255);
  ellipse(x, y, 60, 60);
  fill(0);
  ellipse(x+10, y, 30, 30);
  fill(255);
  ellipse(x+16, y-5, 6, 6);
}

// Draws an eyeball of the given size at x, y
void eye2(int x, int y, float diam){
  fill(255);
  ellipse(x, y, diam, diam);
  fill(0);
  ellipse(x+diam/6, y, diam/2, diam/2);
  fill(255);
  ellipse(x+diam/3.75, y-diam/12, diam/10, diam/10);
}

// draws an X of the given size, weight and color
void drawX(int gray, int weight, int x, int y, int size){
  stroke(gray);
  strokeWeight(weight);
  line(x, y, x+size, y+size);
  line(x+size, y, x, y+size);
}

void threeXs(){
  drawX(160, 20, 30, 355, 60);
  drawX(0, 10, 60, 370, 60);
  drawX(255, 2, 50, 388, 60);
}

37.3. Functions - Hit Detection

Uses functions to return true if a point is in a circle or rectangle, also shows the use of the MousePressed function:

float circleX, circleY;
float circleDY, circleDX;
float rectX, rectY;
float rectWidth, rectHeight;
float diameter;
color circleColor;
color fuchsia = color(255, 0, 255);
color gold = color(255, 215, 0);
color white = color(255);
int transparency;
int dTrans;

void setup() {
  size(500, 500);
  // Starting point of shapes
  circleX = 100;
  circleY = 30;
  diameter = 50;
  rectX = 175;
  rectY = 175;
  rectWidth = 150;
  rectHeight = 150;

  // Initial speed of circle
  circleDX = -2;
  circleDY = 1;

  // color
  circleColor = fuchsia;
  transparency = 128;
  dTrans = 20;
  noStroke();
}

void draw() {
  background(white);

  fill(circleColor);
  ellipse(circleX, circleY, diameter, diameter);
  circleX += circleDX;
  circleY += circleDY;

  // ball hits bottom edge
  if (circleY > 499 - diameter/2) {
    circleDY = -circleDY;
  }
  // ball hits top edge
  if (circleY < 0 + diameter/2) {
    circleDY = -circleDY;
  }
  // ball hits right edge
  if (circleX > 499 - diameter/2) {
    circleDX = -circleDX;
  }
  // ball hits left edge
  if (circleX < 0 + diameter/2) {
    circleDX = -circleDX;
  }

  // Draw Rectangle
  fill(25, 25, 112, transparency);
  rect(rectX, rectY, rectWidth, rectHeight);
}

// If the mouse is pressed in the circle change color
// If pressed in the rectangle make more or less
// transparent
void mousePressed() {
  // If mouse in circle
  if (pointInCircle(mouseX, mouseY,
  circleX, circleY, diameter/2)) {

    // Switch between fuchsia and gold
    if (circleColor == fuchsia) {
      circleColor = gold;
    }
    else {
      circleColor = fuchsia;
    }
  }

  // If mouse is in rectangle
  if (pointInRect(mouseX, mouseY, rectX, rectY,
  rectWidth, rectHeight)) {

    // Make more opaque
    if (transparency >= 255) {
      dTrans = -dTrans;
    }
    // Or more transparent
    else if (transparency <= 0) {
      dTrans = -dTrans;
    }
    transparency += dTrans;
  }
}

// Detects if the point (ptX, ptY) is in the circle
// with centre cX, cY and radius radius, returns true
// if it is, false otherwise
// Long winded version!
//boolean pointInCircle(float ptX, float ptY,
//float cX, float cY, float radius) {
//
//  if (dist(ptX, ptY, cX, cY) < radius) {
//    return true;
//  }
//  else {
//    return false;
//  }
//}

// Detects if the point (ptX, ptY) is in the circle
// with centre cX, cY and radius radius, returns true
// if it is, false otherwise
boolean pointInCircle(float ptX, float ptY,
float cX, float cY, float radius) {

  return dist(ptX, ptY, cX, cY) < radius;
}

// Detects if the point (ptX, ptY) is in the rectangle
// with top left rX, rY and height h and width w,
// returns true if it is, false otherwise
// Long winded version!
//boolean pointInRect(float ptX, float ptY, float rX,
//float rY, float h, float w) {
//
//  if ((ptX > rX && ptX < rX + w) &&
//    (ptY > rY && ptY < rY + h) ) {
//    return true;
//  }
//  else {
//    return false;
//  }
//}

// Detects if the point (ptX, ptY) is in the rectangle
// with top left rX, rY and height h and width w,
// returns true if it is, false otherwise
boolean pointInRect(float ptX, float ptY, float rX,
float rY, float h, float w) {

  return (ptX > rX && ptX < rX + w) &&
    (ptY > rY && ptY < rY + h);
}

37.4. Easing

Shows the use of easing, a technique to slow the speed of an object as it approaches its target:

// Demonstrates easing, where the speed of
// a ball decreases as it gets closer to the
// target -- the mouse
float x = 0;
float y = 0;
float easing = 0.05;

void setup() {
  size(500, 500);
  smooth();
}

void draw() {
  background(0);
  float targetX = mouseX;
  float targetY = mouseY;

  if (abs(targetX - x) > 1) {
    x += (targetX - x) * easing;
  }
  if (abs(targetY - y) > 1) {
    y += (targetY - y) * easing;
  }

  fill(153);
  ellipse(mouseX, mouseY, 20, 20);
  fill(255);
  ellipse(x, y, 40, 40);
}

37.5. Text

Shows how to display text (and how to load a font). Note that the loaded fonts have to have been created and saved in the project’s data folder:

PFont fontRavie;
PFont fontCooper;
String helloString;
String mouseString;
int mousePress;
float mTextY, mTextDY;

void setup(){
  size(500, 500);
  fontRavie = loadFont("Ravie-48.vlw");
  fontCooper = loadFont("CooperBlack-24.vlw");
  mousePress = 0;
  mTextY = 180;
  mTextDY = 1;
}

void draw(){
  background(128);
  fill(255);
  textFont(fontRavie);
  helloString = "Hello World!";
  text(helloString, 50, 200);
  noStroke();
  float sw = textWidth(helloString);
  rect(50, 205, sw, 5);

  textFont(fontCooper);
  fill(255,0,0, 128);
  mouseString = mousePress +
  " mouse clicks";

  text(mouseString, 100, mTextY);

  // Move the text
  mTextY += mTextDY;

  if(mTextY < 10){
    mTextDY = -mTextDY;
  }

  if(mTextY >= 500){
    mTextDY = -mTextDY;
  }
}

void mousePressed(){
  mousePress += 1;
}

37.6. Planets

Draws the closest four planets rotating around the sun, shows the use of transformations and pushMatrix and popMatrix:

// Planet Variables
float angleMercury;
float angleVenus;
float angleEarth;
float angleMoon;
float angleMars;

color colorSun = color(255, 255, 0);
color colorMercury = color(64, 64, 64);
color colorVenus = color(250, 225, 144);
color colorEarth = color(0, 0, 255);
color colorMoon = color(110, 110, 110);
color colorMars = color(250, 48, 8);

// Distances in AUs
float distanceMercury = 0.38;
float distanceVenus = 0.72;
float distanceEarth = 1.0; //149.6 m kms
float distanceMoon;
float distanceMars = 1.52;
float distanceConstant = 150;

// Diameters in kms
float diameterSun = 50; //pixels -- not to scale!
float diameterMercury = 4880;
float diameterVenus = 12104;
float diameterEarth = 12756;
float diameterMoon = 3476;
float diameterMars = 6794;
float diameterConstant = .0025;

// Sppeds comparative to earth rotation
float speedMercury = 4.1; //88 days
float speedVenus = 1.6; //224
float speedEarth = 1.0; //365
float speedMoon = 12.0;
float speedMars = 0.53; //687
float speedConstant = 0.01;

void setup() {
  size(500, 500);
  angleMercury = 0;
  angleVenus = 0;
  angleEarth = 0;
  angleMoon = 0;
  angleMars = 0;

  distanceMercury *= distanceConstant;
  distanceVenus *= distanceConstant;
  distanceEarth *= distanceConstant;
  distanceMoon = 20; //not to scale
  distanceMars *= distanceConstant;

  diameterMercury *= diameterConstant;
  diameterVenus *= diameterConstant;
  diameterEarth *= diameterConstant;
  diameterMoon *= diameterConstant;
  diameterMars *= diameterConstant;

  speedMercury *= speedConstant;
  speedVenus *= speedConstant;
  speedEarth *= speedConstant;
  speedMoon *= speedConstant;
  speedMars *= speedConstant;

  smooth();
}

void draw() {
  background(0); // comment out this line to get a trail

  // draw the sun
  translate(width/2, height/2); // origin = center of the sun
  fill(colorSun);
  ellipse(0, 0, diameterSun, diameterSun);

  // draw the earth rotating around the sun
  pushMatrix();
  angleEarth = planet(distanceEarth, diameterEarth,
  speedEarth, angleEarth, colorEarth);

  // Moon around earth, note it is inside
  // the earth's transformations
  pushMatrix();
  angleMoon = planet(distanceMoon, diameterMoon,
  speedMoon, angleMoon, colorMoon);
  popMatrix();
  popMatrix();

  pushMatrix();
  angleVenus = planet(distanceVenus, diameterVenus,
  speedVenus, angleVenus, colorVenus);
  popMatrix();

  pushMatrix();
  angleMars = planet(distanceMars, diameterMars,
  speedMars, angleMars, colorMars);
  popMatrix();

  pushMatrix();
  angleMercury = planet(distanceMercury, diameterMercury,
  speedMercury, angleMercury, colorMercury);
  popMatrix();
}

// The planet function makes it easy to add planets
float planet(float distance, float diameter,
float speed, float angle, color col){

  rotate(angle);
  translate(distance, 0);
  fill(col);
  ellipse(0, 0, diameter, diameter);
  angle += speed;
  return angle;
}

37.7. Spirals

Example of a class with its own render method that uses transformations:

class Spiral {
  float x;
  float y;
  color fill_color;
  float angle; // angle of rotation

  // Constructor
  Spiral(float init_x, float init_y, color init_c) {
    x = init_x;
    y = init_y;
    fill_color = init_c;
    angle = 0;
  }

  // Draws a rotating spiral
  void render() {
    pushMatrix(); //start transformation
    translate(x, y);
    rotate(radians(angle));
    noStroke();
    float radius = 1;
    fill(fill_color);
    // Draw spiral of small circles (through 6 rotations)
    for (int deg = 0; deg < 360*6; deg += 11) {
      float angle_next = radians(deg);
      float next_x = cos(angle_next) * radius;
      float next_y = sin(angle_next) * radius;
      ellipse(next_x, next_y, 6, 6);
      radius = radius + 0.34;
    }
    popMatrix(); //end transformation
  }
}

Spiral s1;
Spiral s2;

void setup() {
  size(500, 500);
  smooth();

  s1 = new Spiral(100, 100, color(255));
  s2 = new Spiral(400, 400, color(255, 126, 176));
}

void draw() {
  background(196);
  s1.render();
  s1.angle += 1;
  s2.render();
  s2.angle -= 1;
}

37.8. Fountain

Example of a particle system, note that the overall effect is much improved by adding fading to the path of the particles:

class Droplet {
  float x, y;
  float dx, dy;
  float gravity;
  float radius;
  float originX, originY;

  Droplet(float ix, float iy, float idx, float idy,
  float ir, float iox, float ioy) {
    x = ix;
    y = iy;
    dx = idx;
    dy = idy;
    radius = ir;
    originX = iox;
    originY = ioy;
    gravity = 0.1;
  }//constructor

  // Re-use droplets once they have left the window
  void regenerate() {
    if (x - radius > width || x +- radius < 0 ||
      y - radius > height || y +- radius < 0) {
      x = originX;
      y = originY;
      dx = random(-1, 1);
      dy = random(-8, -4);
    }
  }//regenerate

  // Adjust position
  void update() {
    dy += gravity;
    x += dx;
    y += dy;
  }//update

  void render() {
    //fill(0, 0, 255);
    fill(0, 0, 255, 120);
    noStroke();
    ellipse(x, y, radius*2, radius*2);
  }//render
}//Droplet

final int n = 1000;
ArrayList<Droplet> fountain;

void setup() {
  size(500, 500);
  smooth();
  fountain = new ArrayList<Droplet>();

  // Populate the arraylist
  for (int i=0; i < n; i++) {
    float dx = random(-1, 1);
    float dy = -i;
    fountain.add(new Droplet(width/2, height-20, dx, dy,
    1.0, width/2, height-20));
  }
}//setup

void draw() {
  //background(255);
  // fading trails behind droplets
  fill(255, 36);
  rect(0, 0, width, height);

  for (Droplet drop : fountain) {
    drop.update();
    drop.regenerate();
    drop.render();
  }
}//draw

37.9. Fountains

Multiple fountains, shows a fountain class that encapsulates a fountain:

class Droplet {
  float x, y;
  float dx, dy;
  float gravity;
  float radius;

  Droplet(float idx, float idy, float ir) {
    x = 0;
    y = 0;
    dx = idx;
    dy = idy;
    radius = ir;
    gravity = 0.1;
  }//constructor

  // Re-use droplets once they have left the window
  void regenerate() {
    if (y - radius > 0) {
      x = 0;
      y = 0;
      dx = random(-1, 1);
      dy = random(-8, -4);
    }
  }//regenerate

  // Adjust position
  void update() {
    dy += gravity;
    x += dx;
    y += dy;
  }//update

  void render() {
    //fill(0, 0, 255);
    fill(0, 0, 255, 120);
    noStroke();
    ellipse(x, y, radius*2, radius*2);
  }//render
}//Droplet

class Fountain {
  ArrayList<Droplet> water;
  int n;
  float x, y;
  float size;

  Fountain(float ix, float iy, int in, float isz) {
    x = ix;
    y = iy;
    n = in;
    size = isz;
    water = new ArrayList<Droplet>();
    // Populate the arraylist
    for (int i=0; i < n; i++) {
      float dx = random(-1, 1);
      float dy = 0;
      water.add(new Droplet(dx, dy, 1.0));
    }
  }

  void render() {
    pushMatrix();
    translate(x,y);
    scale(size);
    for (Droplet drop : water) {
      drop.update();
      drop.regenerate();
      drop.render();
    }
    popMatrix();
  }
}

ArrayList <Fountain> park;

void setup() {
  size(500, 500);
  smooth();

  park = new ArrayList<Fountain>();
}//setup

void draw() {
  //background(255);
  // fading trails behind droplets
  fill(255, 36);
  rect(0, 0, width, height);

  for(Fountain fount : park){
    fount.render();
  }
}//draw

void mousePressed(){
  int n = (int) random(150, 350);
  float sc = random(.2, .6);
  park.add(new Fountain(mouseX, mouseY, n, sc));
}

37.10. Arrows

Another particle system, that demonstrates the use of transformations to simplify rendering complex objects, and to scale the objects:

class Arrow{
  float x, y;
  float dx, dy;
  float gravity;
  float angle;
  float shaft;

  Arrow(float ix, float iy, float idx,
  float idy, float is){
    x = ix;
    y = iy;
    dx = idx;
    dy = idy;
    shaft = is;
    gravity = 0.1;
    angle = 0;
  }//constructor

  void render(){
    stroke(255);
    pushMatrix();
    translate(x, y); //origin becomes arrow base
    rotate(angle); //rotate in direction of travel
    scale(shaft); //scale based on shaft length
    strokeWeight(1.0 / shaft); //set to 1.0
    line(0, 0, 1, 0);
    line(0.7, -0.3, 1, 0);
    line(0.7, 0.3, 1, 0);
    popMatrix();
  }//render

  void update(){
    dy += gravity;
    x += dx;
    y += dy;
    angle = atan2(dy, dx);
  }//update
}

final int numArrows = 320;
ArrayList<Arrow> quiver;

void setup() {
  frameRate(60);
  size(600, 100);
  smooth();
  quiver = new ArrayList<Arrow>();

  // Create new arrows
  for(int i=0; i<numArrows; ++i){
    float dx = random(1, 8);
    float dy = random(-5, -1);
    quiver.add(new Arrow(0, height/2, dx, dy, 20));
  }
}//update

void draw() {
  background(0);
  for(Arrow a : quiver){
    a.update();
    a.render();
  }
}//draw

37.11. Temple Image

The next three programs use this image (from MS Clip Art):

An image of a temple in Kyoto.

37.12. Moving Image Sections

Image processing application that demonstrates the use of get and set to create image variable that are sections of an image:

PImage temple;
PImage temp;
PImage temp2;
int tempX, tempY;
boolean moving;

void setup(){
  temple = loadImage("temple.JPG");
  size(temple.width, temple.height);
}

void draw(){
  image(temple, 0, 0);
  // Show moving image section
  if(moving){
    fill(128);
    noStroke();
    rect(tempX, tempY, 50 ,50); //grey rectangle
    image(temp, mouseX, mouseY); //moving image
  }
}

// Pick up 50 x 50 section of image
void mousePressed(){
  moving = true;
  temp = get(mouseX, mouseY, 50, 50);
  tempX = mouseX;
  tempY = mouseY;
}

// Swap sections of image
void mouseReleased(){
  // Use underlying image to get the section of the
  // image under the moving image
  temp2 = temple.get(mouseX, mouseY, 50, 50);
  temple.set(tempX, tempY, temp2);
  temple.set(mouseX, mouseY, temp);
  moving = false;
}

37.13. Image Transformations

Image processing application that demonstrates the use of loadPixels and updatePixels to access the components of the pixels array. Also implements an image transformation that changes the red, green and blue components of each pixel in an image:

PImage temple;

void setup(){
  temple = loadImage("temple.JPG");
  size(temple.width, temple.height);

  int count = temple.width * temple.height; // # of pixels
  temple.loadPixels(); // image of temple

  // Load pixels one by one
  loadPixels();
  // Change i+=1 to i+=2 and see the result
  for(int i=0; i < count; i+=1){
    // Change[i] to [i/2] and see the result
    // Change[i] to [count - 1 - 1] and see the result
    pixels[i] = temple.pixels[i];
  }
  updatePixels();
  //invert(); //un-comment to invert
}

void draw(){

}

// Inverts the image
void invert(){
  loadPixels();
  int i = 0;
  for(color c : pixels){
    float r = 255 - red(c);
    float g = 255 - green(c);
    float b = 255 - blue(c);
    pixels[i] = color(r, g, b);
    i++;
  }
  updatePixels();
}

// Replaces pixel with a black pixel
void mousePressed(){
  //set(mouseX, mouseY, color(0));
  loadPixels();
  println(width * mouseY + mouseX);
  pixels[width * mouseY + mouseX] = color(0);
  updatePixels();
}

37.14. Pixel Color Graph

Image processing application that acceses the red, green and blue components of each pixel to draw a graph showing how much colour is in each pixel. Also uses the constrain and map functions. To display the amount of red, green or blue in each pixel press the r, g, and b keys.:

PImage temple;
final int RED = 1;
final int GREEN = 2;
final int BLUE = 3;
int graphColor;

void setup() {
  temple = loadImage("temple.JPG");
  size(temple.width, temple.height+100);
  graphColor = RED;
}

void draw() {
  image(temple, 0, 0);
  // Ensure that row is a legal row of the image
  int row = constrain(mouseY, 0, height - 101);

  // Set the line colour
  if (graphColor == RED) {
    stroke(255, 0, 0);
  }
  else if (graphColor == GREEN) {
    stroke(0, 255, 0);
  }
  else if (graphColor == BLUE) {
    stroke(0, 0, 255);
  }

  // Draw line on image to show row
  fill(128);
  rect(0, height-100, width-1, height-1);
  line(0, row, width, row);

  // Draw graph of the strength of the pixel colour
  for (int i=0; i < width; ++i) {
    stroke(255);
    color c = temple.pixels[row * width + i];

    float lineHeight = 0;
    if (graphColor == RED) {
      lineHeight = red(c);
    }
    else if (graphColor == GREEN) {
      lineHeight = green(c);
    }
    else if (graphColor == BLUE) {
      lineHeight = blue(c);
    }
    lineHeight = map(lineHeight, 0, 255, 0, 100);
    line(i, height, i, height - lineHeight);
  }
}

// Select colour
void keyPressed(){
  if(key == 'r' || key == 'R'){
    graphColor = RED;
  }else if(key == 'g' || key == 'G'){
    graphColor = GREEN;
  }else if(key == 'b' || key == 'B'){
    graphColor = BLUE;
  }
}