Java Graphics2D转换结果与手动转换不匹配

Java Graphics2D转换结果与手动转换不匹配,java,swing,scala,transform,graphics2d,Java,Swing,Scala,Transform,Graphics2d,我使用Java的Graphics2D在一个组件上绘制,使用仿射Transform来操作我的绘图。 Graphics2D为此提供了一种方法变换,它采用仿射变换形式 有时,我需要在不使用内置转换的情况下手动操纵点。 但是,当我尝试使用与Graphics2D.transform相同的变换变换一个点时,有时结果点是不一样的 下面的代码再现了这个问题(这是Scala代码,但我认为您可以想象Java代码): 预期行为 蓝色矩形(手动计算)覆盖了红色矩形(通过变换计算) 有经验的行为 我承认我的转换矩阵不是

我使用Java的Graphics2D在一个组件上绘制,使用仿射Transform来操作我的绘图。 Graphics2D为此提供了一种方法变换,它采用仿射变换形式

有时,我需要在不使用内置转换的情况下手动操纵点。 但是,当我尝试使用与Graphics2D.transform相同的变换变换一个点时,有时结果点是不一样的

下面的代码再现了这个问题(这是Scala代码,但我认为您可以想象Java代码):

预期行为

蓝色矩形(手动计算)覆盖了红色矩形(通过变换计算)

有经验的行为

我承认我的转换矩阵不是真正的整数,但这不应该是问题所在,不是吗

   affineTransform = 1.1, 0.0, 520.55
                     0.0, 1.1, 182.54999999999995
                     0.0, 0.0,    1.0
这是一个错误还是我遗漏了一些深刻的见解

编辑:如果将transformationMatrix设置为

transformationMatrix = new AffineTransform(1.1, 0.0, 0.0, 1.1, 521.55, 183.54999999999995)

在paintComponent的开头。请注意,g是Graphics2D类型。

您的转换基本上只是
(520.55,182.55)
的翻译。因为它有分数像素值,所以它实际上对舍入的选择很敏感。如果启用了抗锯齿功能,实际上会得到一个4像素的红色斑点,覆盖重叠的像素。否则,考虑到舍入为整数和截断为整数之间的不确定性,您看到的行为(不一致)是合理的。

当您执行第一步g.transform(transformationMatrix)时,图形将与已经存在的变换组成。在第二步中,您将使用g.setTransform(新仿射变换)覆盖它,从而丢失以前的变换(如果有)。你假设你回到了起点,但这可能不是真的


在步骤1之前进行getTransform(),在步骤2之后进行getTransform(),以验证它们是否相同。

无论何时处理浮点坐标,如果希望得到正确的结果,都应该使用图形对象的“2D”版本。我并没有从《书》中读到这一点,所以我不能引用,这只是一种体验

这是我的丑陋的java代码,它产生了您所期望的结果

AffineTransform transformationMatrix = AffineTransform.getTranslateInstance(520.55, 182.54999999999995);
transformationMatrix.scale(1.1, 1.1);
((Graphics2D) previewGraphics).transform(transformationMatrix);
previewGraphics.setColor(Color.RED);
((Graphics2D) previewGraphics).fill(new Rectangle(0,0,1,1));
((Graphics2D) previewGraphics).setTransform(new AffineTransform());
Point2D p0 = new Point2D.Double(0, 0);
Point2D pDest = new Point2D.Double();
transformationMatrix.transform(p0, pDest);
previewGraphics.setColor(Color.BLUE);
((Graphics2D) previewGraphics).fill((Shape) new Rectangle2D.Double(pDest.getX(), pDest.getY(), 1, 1));

嗯,你在做两件不同的事情

在(1)中,您将一个形状(它是
矩形
而不是
矩形2D.Double
)置于生成分数坐标的变换之下,这是无关的。它只被绘制为别名,因为您没有设置特定的渲染提示(
RenderingHints.KEY\u ANTIALIASING
->
RenderingHints.VALUE\u ANTIALIAS\u ON
,和
RenderingHints.KEY\u STROKE\u控件
>
RenderingHints.VALUE\u STROKE\u PURE

在(2)中,您将对点进行变换,并将其强制为别名坐标(
,而不是
点2d.Double
)。然后从该点依次构造一个矩形

很明显,可能会有非常不同的事情发生在引擎盖下,我根本不希望转换为整数与在别名图形上下文中绘制浮点形状产生相同的结果

(未经测试)我猜(1)的有效等效语句是


不,这不仅仅是一个翻译,我还有一个1.1的比例因子。我没有打开抗锯齿。那么您认为一个实现是舍入到整数(手动转换),而另一个实现是截断到整数(Graphics2D转换)?听起来似乎有点道理,但我认为这会很奇怪。有没有办法解决这个问题?@knub-1.1的比例因子与取整无关,这就是为什么我说它“基本上”只是一个翻译(而不是说它只是一个翻译)
Graphics2D
默认绘图样式为像素圆形且左上角有偏差,因此,如果绘制一个
N*M
矩形,则得到从原点开始的
N*M
像素,然后在x和y方向得到
N-1
M-1
像素。如果您必须在没有抗锯齿的情况下对齐单个像素,我唯一的建议是手动完成所有运算(并使用
Shape
)。API没有承诺您想要的行为。“Graphics2D默认绘图样式为像素舍入”:据我判断,情况并非如此:(520.55182.55)被舍入(=截断)为(520.182)。还是我遗漏了什么?1.1的因子与四舍五入相关。没有问题,当我将比例因子设置为1.0时(使用相同的翻译)。@knub-那么,这真的很奇怪。它甚至不会影响左上角的位置。在任何情况下,我所说的“像素舍入”是向上舍入和向左舍入,至少对于填充对象是这样。如果使用Rectangle2D.Double(和Point2D.Double)手动执行,会发生什么情况?我想知道调用paint()时是否会激活另一个变换。我会在方法开始时尝试g.getTransform(),并使用结果还原“标准”转换。这也没有帮助。g、 getTransform()返回标识矩阵,保存它并在以后恢复将导致相同的行为。这一点很好!不幸的是,这不是问题所在。使用println(g.getTransform)打印转换将打印标识,使用setTransform而不是transform将导致相同的行为。不起作用。我已经将Graphics2D作为g(这在Scala中自动完成),即使使用Point2D和Rectangle2D,问题仍然存在。您没有遇到此问题的原因是,它仅在平移和缩放的特殊值中出现。此外,问题不在于仿射transform=>transform的舍入(这会正确舍入),而在于Graphics2D内部的舍入(有时会截断而不是转换)
AffineTransform transformationMatrix = AffineTransform.getTranslateInstance(520.55, 182.54999999999995);
transformationMatrix.scale(1.1, 1.1);
((Graphics2D) previewGraphics).transform(transformationMatrix);
previewGraphics.setColor(Color.RED);
((Graphics2D) previewGraphics).fill(new Rectangle(0,0,1,1));
((Graphics2D) previewGraphics).setTransform(new AffineTransform());
Point2D p0 = new Point2D.Double(0, 0);
Point2D pDest = new Point2D.Double();
transformationMatrix.transform(p0, pDest);
previewGraphics.setColor(Color.BLUE);
((Graphics2D) previewGraphics).fill((Shape) new Rectangle2D.Double(pDest.getX(), pDest.getY(), 1, 1));
g.fill(transformationMatrix.createTransformedShape(new Rectangle(0, 0, 1, 1)))