Affine Transforms in Java2D

title page &
other versions

.

 

5. Graphics2D

There are several different ways that one can write code to do affine transforms with Java2D. The simplest way makes use of the new methods in Graphics2D (in package java.awt). These methods let you change the transform associated with the Graphics2D in the most common ways.

This simple component draws an M rotated 30 degrees about the component's center:

class MComponent extends JComponent
{
    public void paintComponent(Graphics gIn)
    {
        Graphics2D g = (Graphics2D)gIn.create();

        g.translate(getWidth() / 2, getHeight() / 2);
        g.rotate(30.0 * Math.PI / 180.0);
        g.setFont(new Font("Sans", Font.BOLD, 24));
        g.drawText("M");

        g.destroy();
}

The coordinate system of the Graphics2D passed to paintComponent (or paint) has 0,0 in the upper left of the coordinate's area, with y increasing down, and x increasing to the right. The translate() moves the 0,0 point to the center of the component's drawing area. The rotate() call then rotates the coordinate system, about that new 0,0 point.

There are several methods for transforming the coordinate system of a Graphics2D:

java.awt
Class Graphics2D

void translate(int x, int y)
void translate(double tx, double ty)
void rotate(double theta)
void rotate(double theta, double x, double y)
void scale(double sx, double sy)
void shear(double shx, double shy)

Each of these methods interprets its arguments in the current coordinate system of the Graphics2D and transforms the coordinate system appropriately.  Subsequent drawing methods will operate in this newly transformed coordinate system.

The beginning of the paintComponent() routine copies the Graphics with create(), and frees the copy with destroy() at the end. This is to ensure that any changes made to the drawing state of the Graphics2D are not accidentally used by other code1. The technique used above isolates all drawing state - such as colors, paints, the composite, clipping region - as well as and the transform.

If, as in this code, only the transform needs to be preserved, it can be done explicitly:

public void paintComponent(Graphics gIn)
{
    Graphics2D g = (Graphics2D)gIn;
    AffineTransform origTransform = g.getTransform();
    ...
    g.setTransform(origTransform);
}

This technique uses more code and is likely to be slower on most platforms (so I'm told by those who know).  However, sometimes it can be useful to get the original transform so that one can restore it in the middle of painting.  For example, if you wanted to draw an image transformed, but then put a text label on top without any transformation.


1In at least one version of Swing, the Graphics passed to paintComponent() is immediately passed afterward onto any borders that need painting. If you left the Graphics transformed some odd way, the border will be transformed as well. Don't count on this, it is not documented behavior, and at least some folks in Sun told me that it was a bug.

Affine Transform Lesson
1. Introduction
2. Ordering
3. Ordering, Part II
4. Try It
5. Graphics2D
6. AffineTransform
7. Wiggly Text
8. Code Examples
9. Links & Credits
Back ] Next ]

 

Back ] Next ]
 
pixel-008000.gif (807 bytes)
Copyright 1999
Glyphic Technology