Chapter 4
2D Transformation
4.1 Introduction
Geometric 2D and 3D transformations used in computer graphics are mappings from one
coordinate system to the other. They play a central role in model construction and
viewing. For example, tools such as rotating, zooming, and mirroring an image found
in most CAD systems are all based on geometric transformations. Other engineering
applications of geometric transformations include creation of animated mechanisms to
study their kinematic and dynamic properties. Due to the importance of geometric
transformations, we shall study 2D and transformations in this and the following
chapters.
Transformation of a point represent the core problem in geometric transformation
because it is the basic geometric element of object. For example, a line may be
defined by the starting and ending points. Curves, surfaces, and solids are, as we
shall see in succeeding chapters, represented by a collection of points. Therefore,
transforming a set of points results in transforming a line, curve, surface, or solid.
For this reason, our study of a geometric transformation focuses on the transformation
of a point that represents an arbitrary point on an object.
Most engineering drawing and design are carried out in the Cartesian coordinate system, which will be referred to as the world coordinate system. It is known that the axes of the Cartesian coordinate system are mutually orthogonal and form a righthanded system. However, most computer monitors use a lefthanded screen coordinate system, which means the origin of the coordinates is at the topleft corner of screen and positive x values are to the right and positive y values are downward. In order to draw an object defined in the world coordinate system on a computer screen, we need to transform the world coordinate system to the screen coordinate system. When the design of geometric object comes to be manufactured, it is then necessary to relate the world coordinate system to the numerical controlled (NC) machine axes, so that coordinate transformations are required here also. In computer graphics, the screen and NC machine coordinate systems are often referred to as a device coordinate (DC) system. Based on the study of 2D transformations in this chapter, we shall also discuss the conversion between the world and DC coordinate system.
Geometric transformations are a wellestablished subject. We have encountered it when we learned the analytic geometry in school and linear algebra in college. Therefore, we shall not discuss the underlying mathematics of geometric transformations in exhaustive detail but emphasize on their implementation and applications.
4.2 Translation
Let (O;x,y) and (O¢;x¢,y¢) denote two coordinate systems with the corresponding axes in these two systems being parallel.
Figure 4.1: Translation
From Figure 4.1 we can immediately see that the coordinate system (O;x,y) is translated
by a displacement vector t, which is defined in terms of (O;x,y) system, so as
to obtain the new coordinate system (O¢;x¢,y¢). We denote a fixed point in the (O;x,y) and (O¢;x¢,y¢) systems by the position vector r and r¢ respectively. Then, the position vector r is related to
r¢ by the equation
The above equation enables us to translate a position vector from one coordinate system
to the other. Defining the following column vectors as
r = 
æ ç
è

 
ö ÷
ø

, t = 
æ ç
è

 
ö ÷
ø

, r¢ = 
æ ç
è

 
ö ÷
ø

, 

we can rewrite the above translation equation as

æ ç
è

 
ö ÷
ø

= 
æ ç
è

 
ö ÷
ø

+ 
æ ç
è

 
ö ÷
ø

, 

which is the form used for implementation.
4.3 Scaling
Sometimes, it is necessary to stretch or shrink a geometric object. Such transformation is known as scaling and can be described by
x¢ = s_{x} x, y¢ = s_{y} y 

where, s_{x} and s_{y} are scalar factors in x and y coordinates. The transformation is called a uniform scaling if s_{x} = s_{y}. Applying a uniform scaling to a geometric object will shrink or stretch the object. However, it will not change the proportion of the object. For example, the ratio of the height to the width of a rectangle will not be affected by a uniform scaling. On the other hand, if s_{x} ¹ s_{y}, the transformation is called a differential scaling which changes the proportion of a transformed object.
Denoting the scaling operation in matrix form as
we may then describe the scaling as

æ ç
è

 
ö ÷
ø

= 
æ ç
è

 
ö ÷
ø


æ ç
è

 
ö ÷
ø

. 

It should be pointed out that we use postmultiplying matrix in this book (i.e., the position vector is given as a column vector and placed on the right of the transformation matrix). In some literature, a premultiplying matrix is used. In this case, a position vector is given as a row vector and placed on the left of transformation matrix. A premultiplying matrix is simply a transpose matrix of a postmultiplying matrix.
Applying a scaling transformation to an image usually change the coordinates of an arbitrary point on the image. If we want to preserve the coordinates of a certain point (e.g., the center of the image), we then need to translate the image so that the point coincides with the origin. After scaling, we then translate the image back. This kind of scaling is sometimes called a scaling about a point.
4.4 Rotation
Let r be the position vector of a point and f the angle between r and the xaxis. Then, r can be explicitly written as
r = 
æ ç
è

 
ö ÷
ø

= 
æ ç
è

 
ö ÷
ø

, 

where, r = r. If the point is rotated about the zaxis by an angle
q, the position vector of the rotated point is given by
r¢ = 
æ ç
è

 
ö ÷
ø

= 
æ ç
è

 
ö ÷
ø

= 
æ ç
è

 
ö ÷
ø

. 

Since x = rcosf and y = rsinf, we have
r¢ = 
æ ç
è

 
ö ÷
ø

= 
æ ç
è

 
ö ÷
ø

= 
æ ç
è

 
ö ÷
ø


æ ç
è

 
ö ÷
ø

. (41) 

The above rotation effect may also be achieved by rotating the coordinate system (O;x,y) about the zaxis by q so as to obtain the new coordinate system (O;x¢,y¢). Accordingly, r¢ is the position vector of the same point r in the new system.
We now look at an example.
 Question: Let the length of a major and minor axis of an ellipse be 2a and 2b respectively, and q the angle between the major axis and the xaxis. Then, derive the expression of an ellipse in the (O;x,y) system.
 Solution: Let (O;[`x],[`y]) be the coordinate system such that the [`x] and [`y]axis are parallel to the major and minor axes of the ellipse. Accordingly, the ellipse can be written as

_ x

= a cosf and 
_ y

= b sinf. 

To derive the x and ycoordinate of the ellipse, we need to rotate the
(O;[`x],[`y]) system about the zaxis by
q such that it coincides with the system (O;x,y). Therefore, by
equation (51), we have

æ ç
è

 
ö ÷
ø

= 
æ ç
è

 
ö ÷
ø


æ ç ç
ç ç è

 
ö ÷ ÷
÷ ÷ ø

= 
æ ç
è

 
ö ÷
ø

. 

The rotation described previously is used to rotate an object about the origin of the coordinate system. If we want to rotate an object about an arbitrary point p, we need to apply first the translation such that the origin of the new coordinate system coincides with the point p, then the rotation about the origin of the new system (i.e., p), and finally the translation to move the coordinate system back to where it was.
4.5 Reflection
Reflecting (or mirroring) an image about yaxis is achieved by simply changing the sign of the xcoordinate. Therefore, we have

æ ç
è

 
ö ÷
ø

= 
æ ç
è

 
ö ÷
ø


æ ç
è

 
ö ÷
ø

. 

Similarly, reflecting an image about the xaxis is achieved by simply
changing the sign of the ycoordinate. However, it is relatively involved to reflect an image about an arbitrary line passing through the origin. Assume the line is represented by a unit vector u. Let f denote the angle between u and the xaxis. Then, the reflection about u is performed as follows:
 Rotating the image about the zaxis by f such
that u coincides with the xaxis. The Rotation matrix is given by
R = 
æ ç
è

 
ö ÷
ø

= 
æ ç
è

 
ö ÷
ø

. 

 Reflecting the image about the xaxis. The reflection matrix is
 Rotating the image such that u is back to its original position. The
rotation matrix is R^{1} = R^{T}.
Therefore, the combined transformation matrix A is
A = R^{T}FR = 
æ ç
è

 
ö ÷
ø


æ ç
è

 
ö ÷
ø


æ ç
è

 
ö ÷
ø

= 
æ ç
è

 
ö ÷
ø

. 

Let r be a position vector of a point. Then, the reflected image r¢ is given by
r¢ = Ar. We may write A as
A = 
æ ç
è

 
ö ÷
ø


æ ç
è

 
ö ÷
ø

. 

Therefore, A may also be obtained by reflecting the image about the xaxis and then rotating the image about the zaxis by 2f.
If the mirror line does not pass through the origin, we may apply the translation such that the starting point a (or any other point on the line) coincides with the origin. After the reflection is performed, we shall need to apply the inverse translation to the image again. For example, to reflect r about the mirror line L(l) = a+lu we would have
4.6 Transformation in homogeneous coordinates
If a rotation R and scaling S are applied one after another to r, then the transformed
image r¢ is given by
Therefore, we may combine two 2×2 transformation matrices into a single 2×2 transformation matrix. However, if a translation is involved, we can not combine a series of transformations to form a single transformation matrix since translations are treated as additions rather than multiplications. In order to treat all transformations in a consistent way so that they can be easily combined, we need to use a homogeneous coordinate system. A position vector r = (x,y)^{T} in a homogeneous coordinate system is represented by r = (w·x, w·y, w)^{T}, where the third coordinate, w may take any nonzero scalar value. For simplicity, however, we usually choose w = 1. In this case, r is represented as r = (x,y,1)^{T}. Accordingly,
 translation is
 scaling is
 and rotation is
With the use of homogeneous coordinates, we are able to give a single transformation matrix representing a combination of several transformations. For example, a rotation of an object about an arbitrary point p = (p_{x},p_{y}) is a combination of translation, rotation, and translation:

æ ç ç
ç è

 
ö ÷ ÷
÷ ø


æ ç ç
ç è

 
ö ÷ ÷
÷ ø


æ ç ç
ç è

 
ö ÷ ÷
÷ ø

. 

By the rule of multiplication of matrices we may write the above transformations in a single transformation matrix as
Similarly, a scaling about an arbitrary point p is

æ ç ç
ç è

 
ö ÷ ÷
÷ ø


æ ç ç
ç è

 
ö ÷ ÷
÷ ø


æ ç ç
ç è

 
ö ÷ ÷
÷ ø

= 
æ ç ç
ç è

 
ö ÷ ÷
÷ ø

. 

As it is seen, the use of homogeneous coordinates enables us to combine several transformations into a single transformation matrix by multiplication. In general, a composition of rotation, scale, reflection, and translation will produce a transformation matrix of the following form:
The upperleft 2×2 is a composite rotation, scale, and reflection matrix, while the t_{x} and t_{y} are composite translations. To transform a position vector r = (w·x, w·y, w)^{T} we have

æ ç ç
ç è

 
ö ÷ ÷
÷ ø

= 
æ ç ç
ç è

 
ö ÷ ÷
÷ ø


æ ç ç
ç è

 
ö ÷ ÷
÷ ø

, 

which involves nine multiplications and six additions. Since the last row of the matrix is mostly zero elements, in the real world computation we may rearrange the transformation as follows to reduce the number of operations
x¢ = a_{00}x+a_{01}y+t_{x}, 

y¢ = a_{10}x+a_{11}y+t_{y}. 

It is noted that the transformation process is reduced to four multiplications and two additions, which is a significant speedup in consideration of transforming hundreds and thousands points that represent your drawing picture.
Finally, we should point out that, since matrix multiplication is in general not commutative, it is of important to keep the correct sequence of multiplications in terms of the order of transformations applied to an image. Only some special cases can we mix the order of multiplications. For example, given a uniform scaling S and a rotation R, we have SR = RS.
4.7 World and device coordinates transformation
As the title indicates, this section concerns the conversion between the world coordinate system and the device coordinate (DC) system. In practice, a DC system can be either your computer screen, printer, or NC machine coordinate system. However, the device coordinate system in this book usually means the coordinate system of your applet's drawing area. As we have mentioned in the previous chapter, the origin (0,0) of your applet's drawing area is, by default, at the topleft corner. Positive x values are to the right and positive y values are downward. Units are measured in pixel values. Therefore, the x and ycoordinate are integers. Such coordinate system arrangement agrees with the coordinate system of your computer screen but disagrees with the world (i.e., the Cartesian) coordinate system we usually work with. For this reason, geometric objects designed in the world coordinate system may not be displayed directly in your applet's drawing area. In this section, we shall show you how to derive the required transformations so that you will be able to display in your applet's drawing area the geometric objects defined in the world coordinate system.
We assume that the DC and world coordinate systems are denoted by (O;x,y) and
(O¢;x¢,y¢).
Since the origin of the DC system is at the topleft corner, the first thing we need to
do is to translate the origin to the leftbottom corner, which is denoted by
O¢ as shown in Figure 4.2.
Figure 4.2: Translating the origin to the leftbottom corner.
Writing this translation explicitly gives x¢ = xO_{x}¢ and y¢ = yO_{y}¢. The next thing we want to do is to change the lefthanded system to the righthanded system. This can be achieved by reflection about the xaxis. Consequently, the relation between the world and DC coordinate systems is
x¢ = xO_{x}¢, y¢ = (yO_{y}¢) = O_{y}¢y. 

As we mentioned, units in your applet's drawing area are measured in pixel values so that
the x and ycoordinate are integers. To match the units used in the world coordinate
system (e.g., millimeters or inches), we need to scale the DC system. A choice of
scaling factor depends on the size and resolution of your computer monitor. An
experimental method to determine a right scale factor is to draw a line whose length is
d in pixels. Then, you measure this line with a ruler. If the length of this line is
d¢ in millimeters, the scale factor is s=d/d¢ which denotes s pixels per millimeter. Therefore, the final transformation between the DC and world coordinate systems is given by
x¢ = 
xO_{x}¢ s

, y¢ = 
O_{y}¢y s

. 

It should be pointed out that the above transformation does not take into consideration
the socalled aspect ratio, which is the ratio between the width and height of
each pixel. Since the pixels of most monitors are taller than they are wide, the aspect
ratio may be critical when you try to draw a figure with symmetric shape such as circles
and squares. For instance, if you use the CGA 320×200 mode, each pixel is
approximately twice as high as it is wide. Therefore, if you draw a 4×4 block of
pixels you will not get a square on the screen. To actually draw a square you must adjust
for the aspect ratio of the mode you are working with. Many graphics packages provide a
method to get the aspect ratio of your monitor. If such a method is not available, you
can get it experimentally by drawing a horizontal and vertical line with length equal to,
say, 1000 pixels, then measuring these two lines in millimeters. The length (in millimeters)
of the horizontal line to that of the vertical line is the aspect ratio of your monitor.
Taking the aspect ratio into account, the transformation from the DC to the world coordinates
is given by
x¢ = 
xO_{x}¢ s

, y¢ = 
O_{y}¢y s×AspectRatio

. 

Conversely, the conversion from the world to DC coordinates is
x = O_{x}¢+s×x¢, y = O_{y}¢s×AspectRatio×y¢. 

Having derived the transformation between the DC and world coordinate systems, we now consider implementation of transformations between two systems. First, let us create a new class GService in the GeomLib directory. The GService class will provide common geometric services to our applets such as conversion between the DC and world coordinate systems. We implement the GService class as follows.
package GeomLib;
import java.awt.*;
public class GService
{
public int xor, yor; // origin of world coordinate system
public double scale; // pixels per millimeter
public double AspectRatio; // width : height
// Constructor initializes origin of world system to topleft corner:
public GService()
{
xor = yor = 0;
scale = 2.631578947368; // machine dependent
AspectRatio = 0.974358974359; // machine dependent
}
// Set the origin of world system to user specified position:
public void SetOrigin(int xor, int yor)
{
this.xor = xor;
this.yor = yor;
}
// Set the world system with respect to user specified information:
public void SetWorldSystem(int xor, int yor, double scale, double AspectRatio)
{
this.xor = xor;
this.yor = yor;
this.scale = scale;
this.AspectRatio = AspectRatio;
}
// Convert the DC to world coordinates:
public void DCToWorld(int x_dc, int y_dc, GPoint pt_world)
{
pt_world.x = (x_dc  xor) / scale;
pt_world.y = (yor  y_dc) / (AspectRatio * scale);
pt_world.z = 0.0;
}
// Convert the world to DC coordinates:
public void WorldToDC(GPoint pt_world, Point pt_dc)
{
pt_dc.x = (int)(xor + scale * pt_world.x);
pt_dc.y = (int)(yor  AspectRatio * scale * pt_world.y);
}
// Convert the world to DC coordinates:
public void WorldToDC(double x, double y, Point pt_dc)
{
pt_dc.x = (int)(xor + scale * x);
pt_dc.y = (int)(yor  AspectRatio * scale * y);
}
}
It should be pointed out that the constructor of GService initializes the
scale factor and aspect ratio with respect to our 21inch monitor with resolution being set to
1024×768. You may need to modify them to match the mode of your monitor. Save the above
code under the name GService.java in the directory GeomLib and compile it to
generate GService.class.
Let us now create an applet to illustrate the conversion of two coordinate systems. In
particular, we want to print out both the DC and world coordinates of the current mouse
position while moving the mouse cursor within the applet's drawing area. We call this
applet the WorldToDC and type the following code:
import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;
import GeomLib.*;
public class WorldToDC extends Applet
implements MouseMotionListener
{
String str;
Point pt_dc = new Point();
GPoint pt_world = new GPoint();
GService gs = new GService();
public void init()
{
// Register event listener:
addMouseMotionListener(this);
// Set origin to the bottomleft corner:
gs.SetOrigin(0, getSize().height);
}
// Required to declare listener interfaces:
public void mouseDragged(MouseEvent evt){}
// Dynamically update pt_dc and pt_world to mouse position:
public void mouseMoved(MouseEvent evt)
{
pt_dc.x = evt.getX();
pt_dc.y = evt.getY();
gs.DCToWorld(pt_dc.x, pt_dc.y, pt_world);
repaint();
}
public void paint(Graphics g)
{
str = String.valueOf(pt_dc.x)+", "+String.valueOf(pt_dc.y);
g.drawString("cursor position in screen coorinates="+str, 5, 15);
str = String.valueOf((float)pt_world.x)+", "+String.valueOf((float)pt_world.y);
g.drawString("cursor position in world coorinates="+str, 5, 285);
}
}
Save the code under the name WorldToDC.java in the directory Ch4 and
compile it to obtain WorldToDC.class. Then, write a WorldToDC.html web
page to invoke the applet which looks similar to that in
Figure 4.3.
Before we move to the next section, let us add a method drawLine() in GService
that draws a straight line defined in the world coordinate system on the screen. This
drawLine() method is the essential tool for us to draw a sophisticated graphics.
The code fragment of this method is given below.
public void drawLine(Graphics g, double x1, double y1, double x2, double y2)
{
Point p1_dc = new Point();
Point p2_dc = new Point();
WorldToDC(x1, y1, p1_dc);
WorldToDC(x2, y2, p2_dc);
g.drawLine(p1_dc.x, p1_dc.y, p2_dc.x, p2_dc.y);
}
4.8 Applications of 2D transformation
We have discussed basic 2D transformations and a conversion between the DC and world
coordinate systems. In this section, we shall put all information together to create
two applets that have practical applications in 2D engineering drawing and simulation.
Our first applet is called the Mechanism that simulates a fourbar linkage
commonly seen in the manufacturing industry. The source code of Mechanism
is listed below.
import java.awt.*;
import java.applet.Applet;
import GeomLib.*;
public class Mechanism extends Applet
{
int width, height;
double r, R;
GService gs = new GService();
public void init()
{
setBackground(Color.lightGray);
r = 20.0;
R = 50.0;
width = getSize().width;
height = getSize().height;
gs.SetOrigin((int)(5*r), height/2);
}
void pause(int time)
{
try{Thread.sleep(time);}
catch(InterruptedException e){}
}
// display the image in the applet then sleep and call repaint
public void paint(Graphics g)
{
double p1[]={0,0}, p2[]={0,0};
double theta=Math.PI/2.0, delta_theta=0.2;
while (true)
{
// Draw axes in red:
g.setColor(Color.red);
gs.drawLine(g, 20.0, 0.0, 80.0, 0.0);
gs.drawLine(g, 0.0, 20.0, 0.0, 20.0);
// Draw linkages:
g.setColor(Color.blue);
p1[0] = r * Math.cos(theta);
p1[1] = r * Math.sin(theta);
gs.drawLine(g, 0.0, 0.0, p1[0], p1[1]);
p2[0] = p1[0] + Math.sqrt(R * R  p1[1] * p1[1]);
gs.drawLine(g, p1[0], p1[1], p2[0], p2[1]);
// Draw sliding bar:
gs.drawLine(g, p2[0]5, p2[1]3, p2[0]+5, p2[1]3);
gs.drawLine(g, p2[0]+5, p2[1]3, p2[0]+5, p2[1]+3);
gs.drawLine(g, p2[0]+5, p2[1]+3, p2[0]5, p2[1]+3);
gs.drawLine(g, p2[0]5, p2[1]+3, p2[0]5, p2[1]3);
pause(100);
theta += delta_theta;
if (theta > Math.PI * 2.0)
theta = 0.0;
// Erase drawings:
g.setColor(Color.lightGray);
g.fillRect(0, 0, width, height);
}
}
}
Save the above code under the name Mechanism.java in the directory ch4
and compile it to obtain Mechanism.class. We then write a HTML web page to invoke
the applet. If everything works, you should see an applet similar to that in
Figure 4.4.
Our next applet is to mirror (i.e., to reflect) a drawing object about an arbitrary reflection
line so as to create a symmetric image about the mirror line. Recalling from the previous
section, a reflection about an arbitrary line involves the following three steps:
 Translating the coordinate system such that the origin of the new system coincides with
the starting point of the mirror line. Denoting the starting point of the line by
p_{0}, the translation matrix in homogeneous coordinate is
 Reflection about the line that passes through the origin. Assume the angle between the mirror line and the xaxis is f. Then, the reflection matrix is
 Translating the coordinate system back to where it was:
Based on the sequence of transformation applied to an object, we have

æ ç ç
ç è

 
ö ÷ ÷
÷ ø


æ ç ç
ç è

 
ö ÷ ÷
÷ ø


æ ç ç
ç è

 
ö ÷ ÷
÷ ø

. 

By the rule of product of matrices we can derive the following combined transformation matrix:

æ ç ç
ç è



x_{0}(1cos2f)y_{0}sin2f 
 

y_{0}(1+cos2f)x_{0}sin2f 
 


 
ö ÷ ÷
÷ ø

. 

Let r = (x,y) denotes an arbitrary point on an image and r¢ = (x¢,y¢) the corresponding point on the mirrored image. The relation between r¢ and r is given by:

æ ç
è

 
ö ÷
ø

= 
æ ç
è

 
ö ÷
ø


æ ç
è

 
ö ÷
ø

+ 
æ ç
è

x_{0}(1cos2f)y_{0}sin2f 
 y_{0}(1+cos2f)x_{0}sin2f 

 
ö ÷
ø

. 

We call this applet the Mirror2d and type the following source code.
import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;
import GeomLib.*;
public class Mirror2d extends Applet
implements ActionListener, MouseListener, MouseMotionListener
{
final int max_num_pts = 20;
int num_pts;
GService gs = new GService();
GPoint line[] = new GPoint[2];
GPoint obj[] = new GPoint[max_num_pts];
GPoint newObj[] = new GPoint[max_num_pts];
boolean DrawObj;
public void init()
{
// Register event listeners:
addMouseListener(this);
addMouseMotionListener(this);
setLayout(new FlowLayout());
Button b;
b= new Button("Draw Object");
b.addActionListener(this);
add(b);
b= new Button("Draw Mirror Line");
b.addActionListener(this);
add(b);
// Inializing other variables:
num_pts = 0;
DrawObj = true;
line[0] = new GPoint();
line[1] = new GPoint();
for (int i=0; i<max_num_pts; i++)
{
obj[i] = new GPoint();
newObj[i] = new GPoint();
}
gs.SetOrigin(0, getSize().height);
setBackground(Color.lightGray);
}
// Set variables with respect to an activated button:
public void actionPerformed(ActionEvent evt)
{
String buttonName = evt.getActionCommand();
if (buttonName.equals("Draw Object"))
{
num_pts = 0;
DrawObj = true;
line[0].SetPoint(0, 0, 0);
line[1].SetPoint(0, 0, 0);
}
else
{
DrawObj = false;
}
repaint();
}
// Required to declare listener interfaces:
public void mouseClicked(MouseEvent evt){}
public void mouseEntered(MouseEvent evt){}
public void mouseExited(MouseEvent evt){}
public void mouseMoved(MouseEvent evt){}
public void mousePressed(MouseEvent evt)
{
if (DrawObj)
{
if (num_pts == 0)
{
gs.DCToWorld(evt.getX(), evt.getY(), obj[num_pts]);
num_pts += 1;
}
if (num_pts < max_num_pts)
{
gs.DCToWorld(evt.getX(), evt.getY(), obj[num_pts]);
num_pts += 1;
}
}
else
{
// Draw mirror line mode:
gs.DCToWorld(evt.getX(), evt.getY(), line[0]);
}
}
public void mouseDragged(MouseEvent evt)
{
if (DrawObj)
gs.DCToWorld(evt.getX(), evt.getY(), obj[num_pts1]);
else
gs.DCToWorld(evt.getX(), evt.getY(), line[1]);
repaint();
}
public void mouseReleased(MouseEvent evt)
{
if (DrawObj)
gs.DCToWorld(evt.getX(), evt.getY(), obj[num_pts1]);
else
gs.DCToWorld(evt.getX(), evt.getY(), line[1]);
}
public void paint(Graphics g)
{
int i;
double dist;
// Draw the geometric object in blue:
g.setColor(Color.blue);
for (i=1; i<num_pts; i++)
gs.drawLine(g, obj[i1].x, obj[i1].y, obj[i].x, obj[i].y);
// Check if the mirror line is valid:
dist = Math.abs(line[1].x  line[0].x) + Math.abs(line[1].y  line[0].y);
if (dist > 1.0)
{
// Draw mirror line in red:
g.setColor(Color.red);
gs.drawLine(g, line[0].x, line[0].y, line[1].x, line[1].y);
// Draw mirrored object in green:
g.setColor(Color.green);
Transform();
for (i=1; i<num_pts; i++)
gs.drawLine(g, newObj[i1].x, newObj[i1].y, newObj[i].x, newObj[i].y);
}
}
void Transform()
{
int i;
double phi, translation_x, translation_y, A[] = new double[4];
// Construct reflection transformation matrix:
phi = Math.atan2(line[1].yline[0].y, line[1].xline[0].x);
A[0] = Math.cos(2 * phi);
A[3] = A[0];
A[1] = A[2] = Math.sin(2 * phi);
translation_x = line[0].x * (1  A[0])  line[0].y * A[1];
translation_y = line[0].y * (1  A[3])  line[0].x * A[2];
// Compute mirrored vertices:
for (i=0; i<num_pts; i++)
{
newObj[i].x = A[0]*obj[i].x + A[1]*obj[i].y + translation_x;
newObj[i].y = A[2]*obj[i].x + A[3]*obj[i].y + translation_y;
}
}
}
Two buttons, Draw Object and Draw Mirror Line, are implemented in
the applet. Clicking the Draw Object button enables you to draw a polygon
that represents a geometric object. The mirrored image is generated when you click
the Draw Mirror Line button and start to draw the mirror line. It is noted
that the ``rubberbanding'' technique discussed in the previous chapter is used here
to create both the polygon and mirror line. Save the above code under the name
Mirror2d.java in the directory ch4 and compile it to obtain
Mirror2d.class. We then write a HTML web page to invoke the applet which
looks similar to that in Figure 4.5.
4.9 Summary and references
Twodimensional translation, scaling, rotation, and reflection are not only the core math
for 2D graphics programming but also the foundation of 3D transformations. Since most of
us are at some extent familiar with basic 2D transformations, we did not discuss the
underlying concepts and mathematics of 2D transformations in exhaustive detail but
emphasized on their implementation and applications.
Most engineers design their models in the Cartesian coordinate system, which is a subject of
Euclidean geometry. Although we can restrict ourselves in the Euclidean geometry, it is
preferred to extend the Euclidean geometry to the projective geometry by introducing the
socalled homogeneous coordinates. With the use of homogeneous coordinates, it is possible
to represent any transformation in the matrix form and hence to combine a number of
transformations into a single transformation. For this reason, we also discussed in this
chapter transformations in homogeneous coordinates.
As an example to illustrate the use of 2D transformations in computer graphics programming, we also discussed how to apply the 2D transformations to derive a system that convert the world coordinates to the device coordinates so that images created in the Cartesian coordinate can be displayed on your computer screen or your applet's drawing area.
Suggested readings for this chapter are:
 Anand, V.B., Computer Graphics and Geometric Modeling for Engineers, 1993, John Wiley & Sons, Inc.
 Ammeraal, L., Computer Graphics for Java Programmers, 1998, John Wiley & Sons, Inc.
 Foley, J.D. et al., Computer Graphics: Principles and Practice, 2nd ed., 1995, AddisonWesley.
 Stephens, R., Visual Basic Graphics Programming, 1997, John Wiley & Sons, Inc.