An Introduction To Programming With Processing

What is the Transformation Matrix

Matrix
The term matrix simply refers to a grid of numbers, which is how Processing stores information about the coordinate system in memory. For example a matrix can be represented as in the illustration to the left.

Transformation Matrix Visualized


We would call this a 4 x 5 matrix meaning that it is made up of 4 rows and 5 columns. This is not an actual representation of a matrix that Processing uses to calculate transforms but simply an example of what a matrix could look like, in fact the matrices that Processing uses are simpler than the previous matrix example. You might hear the term transformation matrix used on occasion, this is just simply referring to the numbers that make up the matrix that the matrix representing the current coordinate system must be processed through in order to produce the representation of the coordinate system in it's transformed state. Although this might sound like a bit of a tongue twister, the concept is less complicated when you think of it in graphical form. Following is an example of what this might look like as a graphical representation, remember the numbers are purely illustrative, and not intended to represent actual numerical data and patterns that Processing calculates:

A Programmatic Solution For Rotating Wheels

Now that we have an idea of what the cart is going to look like when it's moving, lets concentrate on getting the wheels to rotate and translate.

pushMatrix();
  translate(xPos -75 , 250 +25);
  rotate(xPos/wheelBd.width);
  image(wheelBd, 0, 0);
  popMatrix();
  image(cart, 0, 0);
  image(wheelFd, -95, 35);
Wheels
As you can see we have removed the image() function that renders the wheelBd object and placed it between a pushMatrix() and popMatrix() function pair. Between pushMatrix() and popMatrix() we are free to use translate() and rotate() to modify the coordinate system before rendering wheelBd with a call to the image() function. When we originally rendered the three images making up the cart, we had to offset the back wheel and front wheel so that they we in the correct places in relation to the position of the main cart. When performing transformations to an image it's best the have the image transform from the origin. As a result the X and Y parameters of the image() function used to render the image should remain at 0, and translations should be used when the image's X and Y coordinates need to change. This is often the simplest and most logical approach to working with transforms as it ensures that the image's relative distance to the origin is not modified which could lead to unexpected results.

Transforms are more predictable when the image() function's parameters are set to 0, 0 for X and Y. Offsets in these parameters will often result in undesirable transformations.

By setting the imageMode() function to CENTER and the X and Y parameters for the image() function to 0 and 0 we can be assured that the image of the wheel is going to be rendered with it's center at the origin. This is important because all transformations are relative to the origin, so that when we rotate the wheel it will appear to rotate from it's center, this is also due to setting imageMode() to CENTER and not leaving it at it's default of CORNER which would have resulted in the wheel appearing to rotate from it's top left hand corner. Bearing this in mind it is also important that the images that we use for the wheels are square in shape, in other words the image's width should match the same image's height. This creates the impression of the wheels being flat on the ground when they start to rotate. The following statement, is how we remove the image() functions offset and are still able to match the position of the cart with the mouse's X value:
translate(xPos -75 , 250 +25);
The xPos variable has not changed in terms of how it is applied in this sketch, the difference is that the X and Y parameter values that were used in the image() function to render the wheel have now been added to the translate() function's X and Y parameters. The rotate() function follows:
rotate(xPos/wheelBd.width);
Cart PDE
As the xPos variable changes relative to the distance the cart has moved we can use the changing properties of this variable to make the wheels rotate. We can then divide this number by the width of the wheel image which is also the diameter of the circular shape of the wheel. This expression is based on the formula for pi which is pi = circumference/diameter, but it is worth noting that the value returned from our modified expression is not equal to pi, as this would be a constant value as a result xPos is substituted for the circumference of the circle as this will yield a value that changes relative to the distance that the cart has traveled. We can then render the image at the origin after the coordinate system has been transformed, so the image appears to have moved because the coordinate system it is rendered relative to has, by then, been transformed.
image(wheelBd, 0, 0);
Finally use popMatrix() to reset the coordinate system back to it's original transformations. We can then continue to render the main cart and foreground wheel using the same techniques, and not have transformations from one rendering effect another. In the final cart.pde example I've added a shadow, try to figure out how you would go about creating this effect before looking at the code. Here's a hint, I've added four additional images to the sketch.