Basic Principles of Two-Dimensional Graphics (Introduction to Computer Graphics Using Java 2D and 3D) Part 4

Applications of Transformations

This section introduces typical applications and problems that can be solved using geometric transformations.

In computer graphics it is common to define objects in an arbitrary coordinate system in floating point arithmetics, the so-called world coordinates. In order to generate an image of specific objects on the computer screen or another output device, a rectangular clipping region, called viewport, must be specified. The viewport determines which region of the “object world” is visible. Therefore, it is necessary to find a transformation that maps the objects in the viewport, given in world coordinates, to the window coordinates of the computer screen.

Figure 2.19 illustrates the problem and its solution. The rectangle with the lower left corner at (xmin,ymin) and the upper right corner at (xmax,ymax) in the upper left part of the figure defines the viewport or the clipping region, a window specified in the world coordinate system. This part of the object world should be shown on the computer screen in a window defined by the rectangle with (wmin,umin) as its lower left and (wmax,umax) as its upper right corner, given in the coordinates of the computer monitor. These two windows can have different sizes. Even the shape of the two rectangles does not have to coincide.

The mapping from the viewport to the computer monitor can be realised as a composition of the following transformations. In the first step, the viewport window is shifted to the origin of the coordinate system by a suitable translation. In the next step, the viewport window is scaled in such a way that it matches the size of the window on the computer screen.


Fig. 2.19 From world to window coordinates

From world to window coordinates

Finally, another translation will position the scaled window at the correct location on the computer screen. Altogether, the following sequence of elementary geometric transformations has to be carried out:

tmpc009-44_thumb[2][2][2]

In (2.2) o denotes the composition or concatenation of mappings. It should be noted again that the transformations are carried out from right to left in this formula.

As mentioned before, rotations ϋ(θ) defined by a rotation matrix as described on page 25 will always carry out the rotation around the origin of the coordinate system. When the centre of the rotation is supposed to be another point (x0,y0), one can achieve this by applying first a translation shifting the point (x0,y0) to the origin of the coordinate system, then carry out the rotation around the origin and afterwards reverse the initial translation. This means that a rotation through the angle θ around the point (x0,y0) can be implemented by the following composition of transformations:

tmpc009-45_thumb[2][2][2]

In the same way, a scaling can be carried out with respect to the point (x0,y0) instead of the origin of the coordinate system, by simply replacing the rotation in (2.3) by the corresponding scaling.

Pixel coordinates within a window on the computer screen are usually specified in such a way that the first component refers to the pixel column, whereas the second component refers to the pixel row, where pixel rows are counted from top to bottom. As a consequence, the x-axis points as usual from left to right, but the y-axis is oriented in a reverse manner, i.e., it points downwards instead of upwards. When the specification in standard Cartesian coordinates is preferred, one can simply apply suitable geometric transformations, before drawing objects in the window coordinate system. In order to reverse the direction of the y-axis, a reflection with respect to the x-axis has to be carried out. After this reflection, the y-axis points upwards, but the origin of the coordinate system of the window still remains in the upper left corner, so that only objects with negative y-components would be visible. Therefore, after the reflection a translation is also carried out. The translation is a shift in y-direction by the height h of the window, measured in pixels. In this way, the origin of the coordinate system is mapped to the lower left corner of the window. The reflection is a scaling with the parameters sx = 1 and sy = -1. Altogether the transformation is given by

tmpc009-46_thumb[2][2][2]

Geometric Transformations in Java 2D

The class AffineTransform is the basis for geometric transformations in Java 2D where geometric transformations are also implemented by matrices in homogeneous coordinates. The most important constructors are:

•    AffineTransform id = new AffineTransform() generates the identical transformation, which is encoded by the unity matrix. This default constructor generates a transformation that maps every point to itself.

•    The constructor

AffineTransform at = new AffineTransform(a,d,b,e,c,f) allows the specification of an arbitrary transformation matrix. The arguments a,…,f define the six Double-parameters of the transformation matrix. The matrix (2.1) on page 26 shows the assignment of the arguments to the corresponding matrix parameters.

The elementary geometric transformations can be generated in the following way:

Rotation:

• For rotations the class AffineTransform provides the two methods affTrans.setToRotation(angle) that defines the transformation affTrans as a rotation through the angle angle around the origin of the coordinate system and affTrans.setToRotation(angle,x,y) setting the transformation affTrans to a rotation through the angle angle around the point (x, y), respectively.

•    Themethod affTrans.rotation(angle) and the corresponding method affTrans.rotation(angle,x,y) extend the transformation affTrans by a rotation around the origin of the coordinate system or around the point (x,y). This means that the matrix that encodes the original transformation affTrans is multiplied from the right by a matrix for the corresponding rotation. As a consequence, when affTrans is applied to an object, the rotation is carried out first and afterwards the original transformation in affTrans is applied.

Scaling:

•    Themethod affTrans.setToScale(sx,sy) defines the transformation affTrans as a scaling with the scaling factors sx for the x- and sy for the y-axis with respect to the origin of the coordinate system.

•    The method affTrans.scale(sx,sy) extends the transformation affTrans by a corresponding scaling. The extension is to be understood in the same way as in the case of rotations, i.e., as a matrix multiplication from the right.

Shear transformation:

•    Themethod affTrans.setToShear(sx,sy) defines the transformation affTrans as a shear transformation with the shear values sx for the x- and sy for the y-axis with respect to the origin of the coordinate system.

•    The method affTrans.shear(sx,sy) extends the transformation affTrans by a corresponding shear transformation, again in terms of matrix multiplication from the right.

Translation:

•    The method affTrans.setToTranslation(dx,dy) defines the transformation affTrans as translation by the vector (dx, dy)T.

•    The method affTrans.translate(dx,dy) extends the transformation affTrans by a corresponding translation in the same manner as for rotations, scalings and shear transformations, i.e., as matrix multiplication from the right.

The following methods for the composition of such affine transformations are available in the class AffineTransform:

•    By at1.concatenate(at2) the affine transformation at2 is appended to the affine transformation at1 in terms of matrix multiplication from the right, so that first at2 and then the original transformation at1 is carried out.

•    By at1.preConcatenate(at2) the affine transformation at2 is combined with the affine transformation at1 in the sense of matrix multiplication from the left. This means that first the original transformation at1 and then at2 is carried out.

In both cases, the composition of the two transformations is stored in at1.

An affine transformation that is defined as an instance affTrans of the class

AffineTransformcan be applied to a Shape object s in the following way:

tmpc009-47_thumb[2][2][2]

The method createTransformedShape returns the transformed object again as an instance of the class Shape.

In the same way, affine transformations can be applied to an Area object a, for instance in the form

tmpc009-48_thumb[2][2][2]

An affine transformation can also be applied to the Graphics2D object g2d by

tmpc009-49_thumb[2][2][2]

In this case, the corresponding affine transformation will be applied to all objects before they are drawn.

Figures 2.13-2.16 and the images in Fig. 2.18 were generated using these methods in the following programs:

•    ScalingExample.java,

•    RotationExample.java,

•    ShearingExample.java,

•    TranslationExample.java,

•    TransformationOrderExample.java,

•    TransformationOrderExampleT.java,

•    TransformationOrderExampleRT.java,

•    TransformationOrderExampleR.java and

•    TransformationOrderExampleTR.java.

In all of these figures a standard Cartesian coordinate system instead of the window coordinate system was used for the representation of the objects, so that the y-axis points upwards in the window. In order to achieve this effect, an affine transformation according to (2.4) was applied to the Graphics2D object yielding the desired orientation of the y-axis and the desired location of the origin of the coordinate system.

tmpc009-50_thumb[2][2][2]

In (2.4) the values xOffset and yOffset do not occur. This means they are assumed to be zero there. Setting both values to zero means that the origin of the coordinate system is in the lower left corner of the window, a point that is on the margin of the window, and therefore it is not possible to draw this point. Thus, the origin of the coordinate system was slightly shifted to the interior of the window by choosing xOffset = 140 and yOffset = 150, so that the origin of the coordinate system is visible inside the window.

Animation and Movements Based on Transformations

So far, geometric transformations were only applied in a static manner in order to map one coordinate system to another or to describe positioning and deformation of objects. Geometric transformations are also suitable to model moving objects, for instance moving the hands of a clock carrying out a rotation of 6° per second or per minute or 30° per hour. Continuous movements must be decomposed into small stepwise movements which can be described by geometric transformations. The stepwise changes between two images must be small enough and the time between two images in a sequence must be short enough in order to let the movement appear as a continuous or floating movement and not as jumps from one state to another.

Once the movement of an object is modelled by suitable geometric transformations, the object must be drawn, the transformed object has to be computed, the old object must be deleted and the new transformed object has to be drawn again. Deleting the old object causes problems for raster graphics. Deleting means in this case to overwrite the object. In order to overwrite the pixels of the old object a background image must be specified. For more complex objects, overwriting the pixels belonging to the old object would require to render the object again in order to determine which pixels were covered by the old object. Therefore, instead of overwriting single moving objects it is common to write the complete image buffer again, instead of modifying the old one. However, the new image is usually not written directly into the window buffer, but into a virtual buffer which will be copied to the window buffer after the image has been completed. This technique is also called double buffering and will be explained in more detail in Sect. 4.2.

As a simple example for a moving object, a moving clock with a single hand for the seconds is considered sliding from the lower left to the upper right of a display window. The clock itself consists of a quadratic frame and the single rectangular hand for the seconds. The hands for minutes and hours could be modelled in the same way, but are not included here for reasons of simplicity. A translation is needed in order to move the quadratic frame of the clock from the lower left to the upper right corner of the window. This translation must also be applied to the hand for the seconds. In addition to the translation, the hand must also rotate. Figure 2.20 shows some snapshots of the moving clock.

Assuming that the clock should move in each step two units to the right and one unit up, this could be modelled by a translation

tmpc009-51_thumb[2][2][2]

For the hand a rotation of the form

tmpc009-52_thumb[2][2][2]

is needed in order to turn the hand by —π/180, i.e., by 6° clockwise in each step. One end of the hand is fixed in the centre of the clock which is therefore also the centre of the rotation. Even if the clock were initially centred in the origin of the coordinate system, it would move out of the origin after one step already and the centre of rotation for the hand would no longer be the origin.

Fig. 2.20 A moving clock with a rotating hand

A moving clock with a rotating hand

 

There are two possible strategies to describe and handle such composed movements as in the case of the hand, where a translation as well as a rotation has to be carried out. One way would be to track the position of the corresponding object—in this case the hand of the clock—and to shift the centre of the rotation accordingly. In the general case, it is not sufficient to track only the translation of an object. If, for instance, the object is also supposed to be scaled along one of its axes, it is also necessary to know the orientation of the object in order to apply the scaling properly. As an example, the hand of the clock could get longer or shorter while it is rotating without changing its width. In the beginning, the corresponding scaling had to be a scaling along the y-axis. But once the hand starts to rotate, the axis of scaling must also be rotated. Otherwise the hand would not only become longer or shorter, but also thicker or thinner.

Although this strategy for modelling continuous movements of objects is applicable, the following second strategy seems to be more convenient and simpler to implement. The principle of this second strategy is to leave the objects in their initial positions and to compute accumulated geometric transformations which are applied to the objects before they are drawn. For the example of the clock one could use three more transformations in addition to the above-mentioned two transformations:

tmpc009-54_thumb[2][2][2]

Tclock,accTrans and Thand,accRotation are initialised by the identical transformations and are then updated in each step according to the specified equations. Tclock,accTrans specifies the translation which has to be carried out in order to shift the clock from the initial position to the actual position. Tclock,accTrans is applied to the initial frame of the clock that is centred in the origin of the coordinate system. Thand, accRotation describes the rotation around the origin of the coordinate system that must be applied to the hand of the clock in order to reach its actual position within the clock centred around the origin. In addition to this rotation, the hand must also move along with the clock. Therefore, after rotating the hand around the origin, the corresponding translation Tclock,accTrans is also applied to the hand. It is important that the rotation is carried out first and only then the translation is applied.

Scenegraphs as they are introduced in Chap. 5 provide a more convenient alternative to this way of modelling movements and animations.

Next post:

Previous post: