Saint Louis University |
Computer Science 1050
|
Dept. of Math & Computer Science |
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.
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.