Graphics2D 的 transform 方法有什么作用?
What does Graphics2D's transform method do?
在 class 来自 Java 的 Graphics2D 中,它有一个变换方法。
public abstract void transform(AffineTransform Tx)
这是根据文档的描述:
Composes an AffineTransform object with the Transform in this Graphics2D according to the rule last-specified-first-applied. If the current Transform is Cx, the result of composition with Tx is a new Transform Cx'. Cx' becomes the current Transform for this Graphics2D. Transforming a point p by the updated Transform Cx' is equivalent to first transforming p by Tx and then transforming the result by the original Transform Cx. In other words, Cx'(p) = Cx(Tx(p)). A copy of the Tx is made, if necessary, so further modifications to Tx do not affect rendering.
我已经读了好几遍了,但还是不明白它的作用。我也试过寻找其他来源,但g2d的转换方法并不多。
所以我的问题是:转换到底做了什么?我们什么时候使用它?
如果有人能用简单的方式解释一下就太好了。
您可以使用此方法修改 Graphics2D 对象在呈现到设备 space(例如屏幕或一张纸)之前的显示方式。例如,您可以使用它来执行缩放、旋转和剪切图像等操作,以响应用户在您的应用程序中按下 Scale/Rotate/Shear 按钮。
Graphics2D 对象天生带有一个用于跟踪变换的字段,它表示对象将被渲染到的 'device space'(例如,1920 x 1080)的近似值。此转换在运行时计算并应用到对象,以便它在可用的屏幕空间(或打印机页面或投影仪显示器等)中正确呈现
通过应用 transform(AffineTransform Tx)
方法,您告诉系统您想要更改 Graphics2D 对象在最终呈现时的外观;例如,缩放或旋转对象。文档所说的是,您的新变换将应用于 Graphics2D 对象 ,然后 应用其原始变换以使其适合连接到 JVM 所在设备的显示器 运行;所有这些都发生在渲染之前。
可能的答案范围很广,从 "It does what the JavaDoc says" 到完全引用 the graphics programming bible 的几个章节。我会尝试给出一个介于两者之间的答案。它更接近第一个选项,但某些链接指向的信息可能比掌握基本概念所需的信息更详细。
Graphics2D
is an AffineTransform
that describes how objects should be transformed before they are drawn. Such an AffineTransform
is a Matrix that can be imagined as something that modifies the positions of all points of the drawn objects. For example, it can be a rotation matrix 的变换,以便对象在绘制之前旋转。
一个例子:当你在某个JPanel
的paintComponent
方法中,并且得到了Graphics2D
,那么你可以进行绘图操作:
protected void paintComponent(Graphics gr) {
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
...
// Draw a rectangle
g.drawRect(0,0,50,100);
}
在那里绘制的矩形将为 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);
}
现在绘制的矩形将是 100 像素宽和 200 像素高,因为变换会将所有内容缩放 2 倍。您也可以使用执行旋转的变换,例如
g.transform(AffineTransform.getRotateInstance(Math.toDegrees(45)));
这样矩形就会旋转 45 度。
这基本上就是 transform
方法所做的,关于 API 及其效果。
旁注:Graphics2D
的 rotate(...)
、translate(...)
、shear(...)
和 scale(...)
方法确实只是方便的方法。而不是
g.transform(AffineTransform.getRotateInstance(Math.toDegrees(45)));
你可以简单地调用
g.rotate(Math.toDegrees(45));
达到同样的效果。 transform
方法非常通用,因为它可以接收可能在其他地方组成的任意变换矩阵 - 例如在其他一些方法中,Graphics2D
对象根本不可用。
如果您想知道该方法的作用内部:这实际上很简单。它只是执行 Matrix Multiplication。它将 Graphics2D
中包含的 AffineTransform
与传递给 transform
方法的 AffineTransform
相乘。
这种变换矩阵的乘法可以想象为以相反的顺序应用相应的变换:
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);
结果会画出一个矩形,即
- 首先 在 x 和 y 方向缩放 2 倍
- 然后旋转45度
所以结果将是一个更大的旋转矩形。
如果您应用了这样的操作
g.transform(scalingByFactor2);
g.transform(rotationBy45degrees);
然后矩形看起来像一个大的菱形物体。
Edit in response to the comments:
对象看起来不同的原因是转换是独立应用的。也就是说,它们应用于可能已经被其他变换变换过的对象。我认为矩形(或正方形)的示例在这里可能相当直观:
这与通常的绘画或绘图程序基本相同,您对一个对象应用一种变换,然后再应用另一种,变换的顺序会影响结果。
关于transform
和setTransform
方法的区别,一直有一些猜测。正如 MadProgrammer 最后指出的那样:
transform
方法将图形对象的当前变换与新变换连接起来(即:它乘以矩阵)。您可以将其用于 "compose" 多种转换,如上面的旋转和缩放示例所示。
与此相反,Graphics2D#setTransform
方法有完全不同的用途,文档包含相应的警告:
WARNING: This method should never be used to apply a new coordinate transform on top of an existing transform
它应该只用于恢复图形的原始变换,在对 transform
调用的序列之后,如 JavaDoc 的示例所示。
在 class 来自 Java 的 Graphics2D 中,它有一个变换方法。
public abstract void transform(AffineTransform Tx)
这是根据文档的描述:
Composes an AffineTransform object with the Transform in this Graphics2D according to the rule last-specified-first-applied. If the current Transform is Cx, the result of composition with Tx is a new Transform Cx'. Cx' becomes the current Transform for this Graphics2D. Transforming a point p by the updated Transform Cx' is equivalent to first transforming p by Tx and then transforming the result by the original Transform Cx. In other words, Cx'(p) = Cx(Tx(p)). A copy of the Tx is made, if necessary, so further modifications to Tx do not affect rendering.
我已经读了好几遍了,但还是不明白它的作用。我也试过寻找其他来源,但g2d的转换方法并不多。
所以我的问题是:转换到底做了什么?我们什么时候使用它?
如果有人能用简单的方式解释一下就太好了。
您可以使用此方法修改 Graphics2D 对象在呈现到设备 space(例如屏幕或一张纸)之前的显示方式。例如,您可以使用它来执行缩放、旋转和剪切图像等操作,以响应用户在您的应用程序中按下 Scale/Rotate/Shear 按钮。
Graphics2D 对象天生带有一个用于跟踪变换的字段,它表示对象将被渲染到的 'device space'(例如,1920 x 1080)的近似值。此转换在运行时计算并应用到对象,以便它在可用的屏幕空间(或打印机页面或投影仪显示器等)中正确呈现
通过应用 transform(AffineTransform Tx)
方法,您告诉系统您想要更改 Graphics2D 对象在最终呈现时的外观;例如,缩放或旋转对象。文档所说的是,您的新变换将应用于 Graphics2D 对象 ,然后 应用其原始变换以使其适合连接到 JVM 所在设备的显示器 运行;所有这些都发生在渲染之前。
可能的答案范围很广,从 "It does what the JavaDoc says" 到完全引用 the graphics programming bible 的几个章节。我会尝试给出一个介于两者之间的答案。它更接近第一个选项,但某些链接指向的信息可能比掌握基本概念所需的信息更详细。
Graphics2D
is an AffineTransform
that describes how objects should be transformed before they are drawn. Such an AffineTransform
is a Matrix that can be imagined as something that modifies the positions of all points of the drawn objects. For example, it can be a rotation matrix 的变换,以便对象在绘制之前旋转。
一个例子:当你在某个JPanel
的paintComponent
方法中,并且得到了Graphics2D
,那么你可以进行绘图操作:
protected void paintComponent(Graphics gr) {
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
...
// Draw a rectangle
g.drawRect(0,0,50,100);
}
在那里绘制的矩形将为 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);
}
现在绘制的矩形将是 100 像素宽和 200 像素高,因为变换会将所有内容缩放 2 倍。您也可以使用执行旋转的变换,例如
g.transform(AffineTransform.getRotateInstance(Math.toDegrees(45)));
这样矩形就会旋转 45 度。
这基本上就是 transform
方法所做的,关于 API 及其效果。
旁注:Graphics2D
的 rotate(...)
、translate(...)
、shear(...)
和 scale(...)
方法确实只是方便的方法。而不是
g.transform(AffineTransform.getRotateInstance(Math.toDegrees(45)));
你可以简单地调用
g.rotate(Math.toDegrees(45));
达到同样的效果。 transform
方法非常通用,因为它可以接收可能在其他地方组成的任意变换矩阵 - 例如在其他一些方法中,Graphics2D
对象根本不可用。
如果您想知道该方法的作用内部:这实际上很简单。它只是执行 Matrix Multiplication。它将 Graphics2D
中包含的 AffineTransform
与传递给 transform
方法的 AffineTransform
相乘。
这种变换矩阵的乘法可以想象为以相反的顺序应用相应的变换:
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);
结果会画出一个矩形,即
- 首先 在 x 和 y 方向缩放 2 倍
- 然后旋转45度
所以结果将是一个更大的旋转矩形。
如果您应用了这样的操作
g.transform(scalingByFactor2);
g.transform(rotationBy45degrees);
然后矩形看起来像一个大的菱形物体。
Edit in response to the comments:
对象看起来不同的原因是转换是独立应用的。也就是说,它们应用于可能已经被其他变换变换过的对象。我认为矩形(或正方形)的示例在这里可能相当直观:
这与通常的绘画或绘图程序基本相同,您对一个对象应用一种变换,然后再应用另一种,变换的顺序会影响结果。
关于transform
和setTransform
方法的区别,一直有一些猜测。正如 MadProgrammer 最后指出的那样:
transform
方法将图形对象的当前变换与新变换连接起来(即:它乘以矩阵)。您可以将其用于 "compose" 多种转换,如上面的旋转和缩放示例所示。
与此相反,Graphics2D#setTransform
方法有完全不同的用途,文档包含相应的警告:
WARNING: This method should never be used to apply a new coordinate transform on top of an existing transform
它应该只用于恢复图形的原始变换,在对 transform
调用的序列之后,如 JavaDoc 的示例所示。