Graphics2D的transform方法有什么作用?

use*_*460 2 java geometry transform graphics2d

在Java的Graphics2D类中,它有一个transform方法。

public abstract void transform(AffineTransform Tx)
Run Code Online (Sandbox Code Playgroud)

这是根据文档的描述:

根据后指定先应用的规则与此 Graphics2D 中的 Transform 组合一个 AffineTransform 对象。如果当前Transform是Cx,则与Tx合成的结果是新的Transform Cx'。Cx' 成为该 Graphics2D 的当前变换。通过更新的变换 Cx' 变换点 p 相当于先通过 Tx 变换 p,然后通过原始变换 Cx 变换结果。换句话说,Cx'(p) = Cx(Tx(p))。如有必要,会制作 Tx 的副本,因此对 Tx 的进一步修改不会影响渲染。

我读了好几遍了,但还是不明白它的作用。我也尝试过寻找其他来源,但关于 g2d 的转换方法的内容并不多。

所以我的问题是:转换到底做什么?我们什么时候使用它?

如果有人能以简化的方式解释它,那就太好了。

Mar*_*o13 6

可能的答案范围非常广泛,从“它按照 JavaDoc 的说法执行”到完全引用图形编程圣经的几个章节。我会尝试给出一个介于两者之间的答案。它更接近第一个选项,但某些链接指向的信息可能比掌握基本概念所需的信息更详细。

a 的变换Graphics2D描述AffineTransform了对象在绘制之前应如何变换。这样的AffineTransform矩阵可以被想象为修改绘制对象的所有点的位置的东西例如,它可以是旋转矩阵,以便在绘制对象之前旋转对象。

举个例子:当你在paintComponentsome 的方法中JPanel,并且获得了Graphics2D,那么你就可以进行绘图操作:

protected void paintComponent(Graphics gr) {
    super.paintComponent(gr);
    Graphics2D g = (Graphics2D)gr;
    ...

    // Draw a rectangle
    g.drawRect(0,0,50,100);
}
Run Code Online (Sandbox Code Playgroud)

绘制的矩形宽度为 50 像素,高度为 100 像素。

现在,您可以在绘制之前对对象应用新的变换Graphics2D

protected void paintComponent(Graphics gr) {
    super.paintComponent(gr);
    Graphics2D g = (Graphics2D)gr;
    ...

    // Obtain an AffineTransform that describes a scaling
    AffineTransform scalingTransform =      
        AffineTransform.getScaleInstance(2,2);

    // Apply the transform to the graphics
    g.transform(scalingTransform );

    // Draw a rectangle. 
    g.drawRect(0,0,50,100);
}
Run Code Online (Sandbox Code Playgroud)

现在绘制的矩形将是 100 像素宽、200 像素高,因为变换将所有内容缩放为 2 倍。您还可以使用执行旋转的变换,例如

g.transform(AffineTransform.getRotateInstance(Math.toDegrees(45)));
Run Code Online (Sandbox Code Playgroud)

这样矩形就会旋转 45 度。

transform关于 API 及其效果,这基本上就是该方法的作用。

旁注:确实rotate(...)translate(...)shear(...)scale(...)方法Graphics2D只是便捷方法。代替

g.transform(AffineTransform.getRotateInstance(Math.toDegrees(45)));
Run Code Online (Sandbox Code Playgroud)

你可以简单地打电话

g.rotate(Math.toDegrees(45));
Run Code Online (Sandbox Code Playgroud)

以达到同样的效果。该transform方法非常通用,因为它可以接收可能在其他地方组成的任意变换矩阵 - 例如在某些其他方法中,其中对象Graphics2D根本不可用。


如果您想知道该方法内部做了什么:这实际上非常简单。它只是执行矩阵乘法。它将AffineTransform中包含的Graphics2DAffineTransform传递给该transform方法的 相乘。

这种变换矩阵的乘法可以想象为以相反的顺序应用相应的变换:

AffineTransform scalingByFactor2 = 
    AffineTransform.getScaleInstance(2,2);

AffineTransform rotationBy45degrees = 
    AffineTransform.getRotateInstance(Math.toDegrees(45));

g.transform(rotationBy45degrees);
g.transform(scalingByFactor2);
g.drawRect(0,0,50,100);
Run Code Online (Sandbox Code Playgroud)

结果会画出一个矩形,即

  1. 首先在 x 和 y 方向上缩放 2 倍
  2. 然后旋转45度

所以结果将是一个更大的旋转矩形。

如果您应用了这样的操作

g.transform(scalingByFactor2);
g.transform(rotationBy45degrees);
Run Code Online (Sandbox Code Playgroud)

那么这个矩形就会看起来像一个大的菱形物体。

编辑回应评论:

对象看起来不同的原因是变换是独立应用的。也就是说,它们应用于可能已经被其他变换变换过的对象。我认为矩形(或正方形)的例子在这里可能相当直观:

转换顺序

这与通常的绘画或绘图程序基本相同,您对对象应用一种变换,然后再应用另一种变换,变换的顺序会影响结果。


transform关于和方法之间的差异有一些猜测setTransform。正如 MadProgrammer 最后指出的那样:

transform方法将图形对象的当前变换与新变换连接起来(即:将矩阵相乘)。您可以使用它来“组合”多个变换,如上面的旋转和缩放示例所示。

与此相反,该Graphics2D#setTransform方法具有完全不同的目的,并且文档包含相应的警告:

警告:切勿使用此方法在现有变换之上应用新的坐标变换

它只能用于在调用序列之后恢复图形的原始转换,transform如 JavaDoc 示例中所示。