The AffineTransform class describes a two-dimensional affine transformation function, which is a linear transformation from two-dimensional coordinates to two-dimensional coordinates, maintaining the "straightness" of the two-dimensional graphics (Translation: straightness, that is, the straight line after transformation) It's still a straight line without bending, and an arc is still arc) and "parallelness" (Annotation: parallelness, actually refers to keeping the relative positional relationship between two-dimensional figures unchanged, parallel lines are still parallel lines, and the intersection angles of intersecting straight lines remain unchanged. Complex variables learned in sophomore year, " Remember "Conformal Transformation/Conformal Transformation", mathematics is king!). Affine transformation can be achieved through a combination of a series of atomic transformations, including: Translation, Scale, Flip, Rotation and Shear.
This type of transformation can be represented by a 3×3 matrix, whose last row is (0, 0, 1). This transformation matrix transforms the original coordinates (x, y) into the new coordinates (x', y'). Here, the original coordinates and the new coordinates are regarded as the three-dimensional column vector of the last row (1). The original column vector is transformed by left multiplication The matrix gets new column vectors:
[x'] [m00 m01 m02] [x] [m00*x+m01*y+m02] [y'] = [m10 m11 m12] [y] = [m10*x+m11*y+m12] [1 ] [ 0 0 1 ] [1] [ 1 ]
Several typical affine transformations:
public static AffineTransform getTranslateInstance(double tx, double ty)
Translation transformation, move each point to (x+tx, y+ty), the transformation matrix is:
[ 1 0 tx ] [ 0 1 ty ] [ 0 0 1 ]
(Annotation: Translation transformation is a kind of "rigid-body transformation". Anyone who has studied physics in middle school knows what a "rigid body" is. It is an ideal object that will not deform. Of course, translation will not change the two-dimensional graphics. In the same way, the "rotation transformation" below is also a rigid body transformation, and "scaling" and "cross-cutting" will change the shape of the graphic.)
public static AffineTransform getScaleInstance(double sx, double sy)
Scaling transformation enlarges (reduces) the abscissa of each point to sx times, and enlarges (reduces) the ordinate to sy times. The transformation matrix is:
[ sx 0 0 ] [ 0 sy 0 ] [ 0 0 1 ]
public static AffineTransform getShearInstance(double shx, double shy)
Shear transformation, the transformation matrix is:
[ 1 shx 0 ] [ shy 1 0 ] [ 0 0 1 ]
Equivalent to a combination of a transverse shear and a longitudinal shear
[ 1 0 0 ][ 1 shx 0 ] [ shy 1 0 ][ 0 1 0 ] [ 0 0 1 ][ 0 0 1 ]
(Translation note: "Shear transformation" is also called "miscut transformation", which refers to properties similar to quadrilateral instability. Have you ever seen the iron sliding doors in small shops on the street? Imagine the iron bars above. The process of rhombus pulling is the process of "wrong cutting").
public static AffineTransform getRotateInstance(double theta)
Rotation transformation, the target graphic rotates theta radians clockwise around the origin, the transformation matrix is:
[ cos(theta) -sin(theta) 0 ] [ sin(theta) cos(theta) 0 ] [ 0 0 1 ]
public static AffineTransform getRotateInstance(double theta, double x, double y)
Rotation transformation, the target graphic is rotated clockwise by theta radians with (x, y) as the axis, and the transformation matrix is:
[ cos(theta) -sin(theta) xx*cos+y*sin] [ sin(theta) cos(theta) yx*sin-y*cos ] [ 0 0 1 ]
It is equivalent to the composite of two translation transformations and one origin rotation transformation:
[1 0 -x][cos(theta) -sin(theta) 0][1 0 x] [0 1 -y][sin(theta) cos(theta) 0][0 1 y] [0 0 1 ] [0 0 1][0 0 1]
In geometry, a vector space undergoes a linear transformation followed by a translation. This process is called affine transformation or radial mapping.
It can be expressed simply as: y = Ax + b, where the subscripted letter represents a vector and the bold letter A represents a matrix.
It doesn’t matter if you can’t understand it for the time being (I don’t understand it either^_^#), it doesn’t matter, we only use a few special cases of it here: translation and rotation transformation.
As usual, let’s post the entire code below:
import java.applet.Applet;import java.awt.BorderLayout;import java.awt.Checkbox;import java.awt.CheckboxGroup;import java.awt.Color;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.Panel;import java.awt.event.ItemEvent;import java.awt.event.ItemListener;import java.awt.geom.AffineTransform;import java.awt.geom.Rectangle2D;import java.util.Random;public class AffineTest extends Applet implements ItemListener{ private Rectangle2D rect; private Checkbox rotateFirst; private Checkbox translateFirst; public void init() { setLayout(new BorderLayout()); CheckboxGroup cbg = new CheckboxGroup(); Panel p = new Panel(); rotateFirst = new Checkbox("rotate, translate", cbg, true); rotateFirst.addItemListener(this); p.add(rotateFirst); translateFirst = new Checkbox ("translate, rotate", cbg, false); translateFirst.addItemListener(this); p.add(translateFirst); add(p, BorderLayout.SOUTH); rect = new Rectangle2D.Float(-0.5f, -0.5f, 1.0f, 1.0f); } public void paint(Graphics g) { Graphics2D g2d = (Graphics2D)g; final AffineTransform identify = new AffineTransform (); boolean rotate = rotateFirst.getState(); Random r = new Random(); final double oneRadian = Math.toRadians(1.0); for(double radians = 0.0; radians < 2.0*Math.PI ; radians += oneRadian) { g2d.setTransform(identify); if(rotate) { g2d.translate(100, 100) ; g2d.rotate(radians); } else { g2d.rotate(radians); g2d.translate(100, 100); } g2d.scale(100, 100); g2d.setColor(new Color(r.nextInt())); g2d.fill(rect); } } @Override public void itemStateChanged(ItemEvent arg0) { // TODO Auto-generated method stub repaint(); }}import java.applet.Applet;import java.awt.BorderLayout;import java.awt.Checkbox;import java.awt.CheckboxGroup;import java.awt.Color;import java.awt.Graphics;import java.awt.Graphics2D;import java .awt.Panel;import java.awt.event.ItemEvent;import java.awt.event.ItemListener;import java.awt.geom.AffineTransform;import java.awt.geom.Rectangle2D;import java.util.Random;public class AffineTest extends Applet implements ItemListener{ private Rectangle2D rect; private Checkbox rotateFirst; private Checkbox translateFirst; public void init() { setLayout(new BorderLayout()); CheckboxGroup cbg = new CheckboxGroup(); Panel p = new Panel(); rotateFirst = new Checkbox("rotate, translate", cbg, true); rotateFirst.addItemListener(this); p.add(rotateFirst); translateFirst = new Checkbox ("translate, rotate", cbg, false); translateFirst.addItemListener(this); p.add(translateFirst); add(p, BorderLayout.SOUTH); rect = new Rectangle2D.Float(-0.5f, -0.5f, 1.0f, 1.0f); } public void paint(Graphics g) { Graphics2D g2d = (Graphics2D)g; final AffineTransform identify = new AffineTransform (); boolean rotate = rotateFirst.getState(); Random r = new Random(); final double oneRadian = Math.toRadians(1.0); for(double radians = 0.0; radians < 2.0*Math.PI ; radians += oneRadian) { g2d.setTransform(identify); if(rotate) { g2d.translate(100, 100) ; g2d.rotate(radians); } else { g2d.rotate(radians); g2d.translate(100, 100); } g2d.scale(100, 100); g2d.setColor(new Color(r.nextInt())); g2d.fill(rect); } } @Override public void itemStateChanged(ItemEvent arg0) { // TODO Auto-generated method stub repaint(); }}
From comparison, it can be seen that the order of affine transformation cannot be exchanged casually.