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

时间:2012-07-09 20:23:20

标签: java swing scala transform graphics2d

我正在使用Java的Graphics2D在一个组件上使用AffineTransform来操作我的绘图。 Graphics2D为此提供了一个方法转换,它采用了AffineTransform。

有时我需要手动操作一个点而不使用内置转换。 但是当我尝试使用相同的变换转换一个点时,我给了Graphics2D.transform有时结果点不一样。

以下代码重现了该问题(它是Scala代码,但我认为您可以想象Java代码。):

   var transformationMatrix = new AffineTransform()
   /*
    * transformationMatrix is modified throughout the program
    * ...
    */
   override def paintComponent(g: Graphics2D) = {
      super.paintComponent(g)
      /* 1. transform using graphics transform */
      g.transform(transformationMatrix)
      g.setColor(Color.RED)
      g.fill(new Rectangle(0, 0, 1, 1))
      /* 2. transform point manually */
      g.setTransform(new AffineTransform) // reset transformation to standard
      val p0 = new Point(0, 0)
      val pDest = new Point()
      transformationMatrix.transform(p0, pDest)
      g.setColor(Color.BLUE)
      g.fill(new Rectangle(pDest.x, pDest.y, 1, 1)
   }

预期行为

蓝色矩形(手动计算)透过红色矩形(通过变换计算)。

有经验的行为

The blue rectangle has an offset of 1

我承认我的transformationMatrix并不是真正的整数,但那不应该是问题,是吗?

   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类型。

4 个答案:

答案 0 :(得分:6)

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

答案 1 :(得分:5)

嗯,你做了两件不同的事情。

在(1)中,您正在对产生分数坐标的变换进行形状(与Rectangle而不是Rectangle2D.Double无关)。它只是涂有别名,因为您没有设置特定的渲染提示(RenderingHints.KEY_ANTIALIASING - > RenderingHints.VALUE_ANTIALIAS_ONRenderingHints.KEY_STROKE_CONTROL - > RenderingHints.VALUE_STROKE_PURE)。

在(2)中,您将置于变换中,将其强制变为别名坐标(Point而不是Point2D.Double) 。然后从那一点开始连续构造一个矩形。

很明显,幕后可能会发生非常不同的事情,我完全不希望转换为整数点,而在混叠图形上下文中绘制浮点形状会产生相同的结果。

(没有测试)我猜想(1)的有效等效语句是

g.fill(transformationMatrix.createTransformedShape(new Rectangle(0, 0, 1, 1)))

答案 2 :(得分:2)

当您执行第一步g.transform(transformationMatrix)时,Graphics会使用已存在的转换组成该步骤。在第二步,你用g.setTransform(新的AffineTransform)重写它,从而失去了先前的转换(如果有的话)。你假设你回到了开始,但可能不是真的。

在步骤1之前创建一个getTransform(),在步骤2之后创建另一个,以验证它们是否相同。

答案 3 :(得分:1)

每当使用浮点坐标时,如果想要正确的结果,应使用“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));