Java中的仿射变换是如何工作的?

8
我在我的Java项目中使用了仿射变换来旋转一个字符串,但我并不是一位有经验的程序员,所以完成这个看似小任务花费了我很长时间。现在我终于让它基本上按照我的希望工作了,但它的精度还不够...然而。
由于尝试和误差很多,而且阅读了仿射变换的描述,我仍然不太确定它到底是做什么的。目前我认为知道的是,我拿到一个字符串,并定义了字符串的中心(或想要围绕其旋转的点),但矩阵又是从哪里来的呢?(显然我不是很清楚哈哈)
能不能有人尝试用其他方式解释一下仿射变换如何工作,而不是Java文档中的描述呢?也许这可以帮助我微调实现,而且我只是真的想知道:)
先谢谢了。

2
这更像是一个数学问题而不是编程问题。请查看维基百科关于它的页面: http://en.wikipedia.org/wiki/Affine_transformation不过,要理解它可能并不比JavaDoc更容易。不幸的是,这只是那些你必须通过刻苦学习来掌握的事情之一,以我个人的看法。 - brindy
5个回答

6
要了解什么是仿射变换以及它是如何工作的,请参阅维基百科文章
一般来说,仿射变换是一种线性变换(如缩放或反射),可以实现为乘以特定矩阵,然后加上向量进行平移。因此,要计算每个像素[x,y]的新位置,您需要将其乘以特定矩阵(进行线性变换),然后加上特定向量(进行平移)。

4
除了其他答案之外,这里是更高层次的视角:
- 屏幕上的点有x和y坐标,即可以写成向量(x,y)。更复杂的几何对象可以被认为是由一组点描述的。 - 向量(点)可乘以矩阵,结果是另一个向量(点)。 - 有些特殊的(即巧妙构造的)矩阵,当与向量相乘时会产生旋转、缩放、扭曲或稍微骗一下移动输入点的效果。 - 基本上就是这样。这种方法还有一些更高级的功能: - 如果您将2个矩阵相乘,则再次得到一个矩阵(至少在这种情况下;不要挑毛病;-) )。 - 如果您乘以2个等效于2个几何变换的矩阵,则得到的矩阵等效于按顺序进行2个几何变换(顺序很重要)。 - 这意味着您可以在单个矩阵中编码任意链的这些几何变换。而且您可以通过乘以各个矩阵来创建此矩阵。 - 顺便说一句,这也适用于3D。
有关详细信息,请参见其他答案。

3
除了其他人已经给出的答案外,我想展示一个实用的技巧,即在旋转字符串或其他对象时我通常应用的模式:
  1. 通过应用 translate(-x,-y) 将旋转点 (x,y) 移动到空间原点。
  2. 进行旋转 rotate(angle)(可能还会进行缩放)。
  3. 通过 translate(x,y) 将所有内容移回原始点。
请记住,您必须按照相反的顺序应用这些步骤(参见 trashgod 的答案)。
对于字符串,我通常使用第一次平移将边界框的中心移动到原点,并使用最后一次平移将字符串移动到屏幕上实际出现中心的位置。然后,我可以在任何位置简单地绘制字符串。
Rectangle2D r = g.getFontMetrics().getStringBounds(text, g);
g.translate(final_x, final_y);
g.rotate(-angle);
g.translate(-r.getCenterX(), -r.getCenterY());
g.drawString(text, 0, 0);

或者,另一种选择是
Rectangle2D r = g.getFontMetrics().getStringBounds(text, g);
AffineTransform trans = AffineTransform.getTranslateInstance(final_x, final_y);
trans.concatenate(AffineTransform.getRotateInstance(-angle));
trans.concatenate(AffineTransform.getTranslateInstance(-r.getCenterX(), -r.getCenterY()));
g.setTransform(trans);
g.drawString(text, 0, 0);

2
实际上,我发现理解AffineTransform有两点是有帮助的:
  1. 您可以转换任何实现Shape接口的图形上下文Graphics2D或类,如此处所述。

  2. 连接的变换具有明显的后指定先应用顺序,也在此处提到。


2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接