这里我们要用java 2-D来进行坐标空间中的变换。看到这里貌似要去复习线性代数了(呜呜)。
这里主要讲的是仿射变换的入门,我们这一次主要是要尝试用实例证明:仿射变换的顺序是不可逆的。
我们将要看到的程序实现了两种情况,一种是先平移,再旋转;另一种是先旋转,在平移。为了能更好的理解程序,首先得了解一些基本内容。
AffineTransform,即仿射变换。那么什么是仿射变换呢?几何中,一个向量空间进行一次线性变换并接上一个平移,这么一个过程就称为仿射变换或放射映射。
可以简单地表示为:y = Ax + b ,其中有下标的字母表示向量,而粗体的字母A表示一个矩阵。
如果暂时无法理解也没有关系(我也没理解 ^_^#),没关系,我们这里仅使用了它的几个特例:平移和旋转变换。
按照惯例,下面先把整个代码贴出来:
- 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();
- }
- }
嗯,下面我们一步一步来看程序是怎样实现的。
一开始,我们定义了一个CheckboxGroup,它可以看作是用来存储Checkbox的一个容器。然后我们又定义了两个Checkbox用来选择是先旋转呢,还是先平移呢。成员变量中还有一个Rectangle2D,用来作为变换的基准。
接下来,我们在init函数中将Checkbox定义好,然后再将CheckboxGroup填满,最后初始化了Rectangle2D的大小。
在重写paint函数的时候,我们利用AffineTransform作[0, 2pi]的旋转变换以及平移变换。我们通过Checkbox的选择来判断这两个操作的先后顺序。
程序的结果如下所示:
对比可知,仿射变换的顺序是不能随便交换的。好吧,下次学习更多的java-2D的内容。