Course Home | Documentation | Lab Hours/Tutoring | Projects | Quizzes | Schedule | Submit

Saint Louis University

Computer Science 1050
Introduction to Computer Science: Multimedia

Michael Goldwasser

Spring 2016

Dept. of Math & Computer Science

Lecture Notes: Transformations


I do not intend for these notes to be the primary introduction of the topic. Instead, I simply wish to note that transformations can be very useful when combined with user-defined functions for drawing composite shapes.

In previous notes, we introduced an example of a user-defined function to draw a person, allowing us to compose images such as the following.

To allow the user to place this function at any location and drawn at any scale, our prevous implemention appeared as follows:

void person(int x, int y, int w) {
  line(x-w/2, y, x, y-w);          // left leg
  line(x+w/2, y, x, y-w);          // right leg
  line(x, y-w, x, y-2*w);          // trunk
  line(x, y-1.5*w, x-w/2, y-2*w);  // left arm
  line(x, y-1.5*w, x+w/2, y-2*w);  // right arm
  ellipse(x, y-2.5*w, w, w);       // head
}
Recall that the geometry expressed here matches the following model:

Although this geometry is not too cumbersome, another approach is to think about the geometry on a fixed scale about the origin, and then to use transformations to reposition and resize the figure. In this case, we might model the geometry instead as follows:

which then allows the absolute geometry:

  line(-5, 0, 0, -10);         // left leg
  line(5, 0, 0, -10);          // right leg
  line(0, -10, 0, -20);        // trunk
  line(0, -15, -5, -20);       // left arm
  line(0, -15, 5, -20);        // right arm
  ellipse(0, -25, 10, 10);     // head

We could still provide a similar person function with parmaeters x, y, and w, written as follows:

void person(int x, int y, int w) {
  pushMatrix();
  translate(x,y);
  scale(w/10.0);               // e.g. width of 20 requires scale 2
  line(-5, 0, 0, -10);         // left leg
  line(5, 0, 0, -10);          // right leg
  line(0, -10, 0, -20);        // trunk
  line(0, -15, -5, -20);       // left arm
  line(0, -15, 5, -20);        // right arm
  ellipse(0, -25, 10, 10);     // head
  popMatrix();
}

It is worth noting that this implementation of the person() function does not have the identical outward behavior as our original. The distinction is that the original used a strokeWeight of 1 pixel no matter what width the person was drawn with. In our new version, although strokeWeight is still set at 1, once we scale the coordinate system it will be drawn with a visual thickness that varies with the width of the person. This is because the strokeWeight of 1 virtual pixel could become many pixels wide when the coordinate system has been scaled. If using our original setup function, the result produced is as follows:

If we wish to return to a behavior with the stroke weight appearing at one actual pixel for any scale, we can additionally adjust the strokeWeight within the function to counteract the effect of the scale. This implementation appears as follows:

void person(int x, int y, int w) {
  pushMatrix();
  pushStyle();
  translate(x,y);
  scale(w/10.0);
  strokeWeight(10.0/w);
  line(-5, 0, 0, -10);         // left leg
  line(5, 0, 0, -10);          // right leg
  line(0, -10, 0, -20);        // trunk
  line(0, -15, -5, -20);       // left arm
  line(0, -15, 5, -20);        // right arm
  ellipse(0, -25, 10, 10);     // head
  popMatrix();
  popStyle();
}

Download the complete .pde file for this version of our implementation.

Allow the Caller to Manage the Transforms

Another common approach that can be used is to provide a function that draws a composite shape at a fixed size and location (typically relative to the origin). Then, instead of parameterizing the translational offset and scale factor as parameters to the function, we can leave that responsibility to the caller. This is effectively a tradeoff in complexity, as the function becomes simpler but the surrounding code calling the function is more complex. But it does allow great flexibility (and could be used similarly to easily rotate the person).

A complete version of this code appears as follows:

void setup() {
  size(200,200);
  background(255);
  
  pushMatrix();
  translate(50, 150);  // move origin to (50,150)
  scale(3);            // will create person of width 30
  person();
  popMatrix();
  
  pushMatrix();
  translate(100, 180); // move origin to (100,180)
  scale(2);            // will create person of width 20
  person();
  popMatrix();

  pushMatrix();
  translate(150, 150); // move origin to (150,150)
  scale(3);            // will create person of width 30
  person();
  popMatrix();
}

/*
  Draw a person centered above the origin having width 10.
*/
void person() {
  line(-5, 0, 0, -10);         // left leg
  line(5, 0, 0, -10);          // right leg
  line(0, -10, 0, -20);        // trunk
  line(0, -15, -5, -20);       // left arm
  line(0, -15, 5, -20);        // right arm
  ellipse(0, -25, 10, 10);     // head
}

Download the complete .pde file for this version of our implementation.


Michael Goldwasser
CSCI 1050, Spring 2016
Last modified: Tuesday, 16 February 2016
Course Home | Documentation | Lab Hours/Tutoring | Projects | Quizzes | Schedule | Submit