COMP 310
Fall 2012 |
## Lec11: Factories, cont. & Transforming How We Paint |

*Note**:
The code for dynamic class loading has been updated to better handle changes in
the way that Java orders multiple constructors dring the reflection discovery
process. Please see the page on *
*
dynamic class loading in the Java Resources site*.

Is updating the state of the ball the only place where strategies might be useful? Take a look at the Fishworld Demo (We will do command dispatching shortly. Command dispatching is separate from the painting features in Fishworld.)

How does Fishworld create fish that are not only the correct size, but are always swimming forward? How does it create different sizes and orientations of the same image?

Remember that a fish (ball) knows where it is and which way it is going because it has a position and a velocity. It has a radius too, so it knows its size as well. Thus any given ball can take a common representation of an image, e.g. a fish, scale it as per its radius, rotate it as per its velocity and translate it as per its position and end up with an image that is always oriented correctly with respect to its movement. The mathematical process of scaling, rotating and translating is called an "affine transform".

*An affine transform is the mathematical
process of scaling (making larger or smaller), rotating (pivoting around the
origin) and translating (moving a specified distance and direction) of a point
in space. An affine transform is a single operation
that does all three transformations. Remember that a point (coordinate in
space, e.g. java.awt.Point) is really a vector from the origin,
so a affine transformation technically transforms vectors, not geometrical points.*

Affine transforms may seem mathematically
daunting, but they are actually quite straightforward. Plus, Java
provides an
AffineTransform class that
encapsulates the mathematics and makes dealing with affine transformation very
easy. Translation: we never have to fuss with the math, we
just use the results. *Gotta love that! *

Example of the operations involved in a *
single* Affine transformation, showing the individual steps of rotating,
scaling and translating:

Original vector: then Rotated vector:

then Scaled vector and then Translated vector:

Note that the order of operation is important:

Original vector: then Rotated vector: then Translated vector:

as compared to

Original vector: then Translated vector: then Rotated vector:

In fancy mathematical words, we same that
rotation and translation are *non-commutative*. A net
Affine transformation is thus dependent on not only what operations (rotate,
scale, translate) are defined, but also in what order those operations are
defined.

So, what all this boils down to is the following: In order to put an visual representation of a ball onto the screen, we need to know 3 things:

Property we need: |
Where we get it: |

1. The scaling of the ball with respect to some "unit" size | The ball's radius |

2. The rotational orientation of the ball | The direction of the ball's velocity |

3. Translation from the origin of the display component | The ball's x-y location. |

With the above 3 things, we can set up an AffineTransform object and it will do all the math to get our ball's visual representation to the correct location on the screen, with the correct size and with the correct orientation!

But what is this "visual representation"? Notice a key phrase in the above table: "with respect to some 'unit' size".

*All we need to do is to define a unit-sized visual
representation of the ball and the affine transform process will take care of
sizing it up, orienting it and locating it on the screen.*

This unit sized representation is what is called a "**prototype**"
representation of the ball. We are implementing what is known as the
Prototype Design
Pattern. Prototypes are another way in which we can look at the
creational process of objects.

**Prototypes are objects that are used to as a
templates with which to create the actual objects to be used.
**

So what we will do is to define a unit-sized prototype that the affine transform will use to create a full-sized, properly located and oriented visual representation of the ball.

Luckily, Java provides one interface and one classe that make our lives much easier in this regards (though it would have been even easier if the two were abstractly related!):

**
java.awt.Shape** -- An interface that represents a shape as a
set of connected points. There are many supplied implementations of
Shape , including and not limted to, lines,
arcs, ellipses, rectangles, polygons, etc. The points that define these
shapes are defined on a double-valued x-y coordinate system. Thus
the unit size (distance) is defined to be 1.0.

**
java.awt.Image** -- A class that represents an image, such as
one from a GIF, JPG or PNG file. Due to the interger coordinate
system used to locate pixels in an image, Image objects need to have their unit
size defined as the average of the width and height of the image in pixels.
Furthermore, since the useful image may not completely fill the rectangular
image area, a "* fill factor*" needs to be specified that
gives the ration of the size of the useful part of the image to the entire
image. A fill factor is necessarily always a values less than 1.0.

AffineTransform objects can be used to transform both Shape and Image objects.

© 2012 by Stephen Wong