Java – 子像素线精度是否需要AffineTransform?

我之前从未使用过Java绘图方法,所以我决定深入研究并创建一个模拟时钟作为PoC。 除了手之外,我画了一个钟面,包括刻度标记,分钟/小时。 我使用简单的sin / cos计算来确定圆周线的位置。

但是,我注意到由于分钟刻度非常短,因此线条的角度看起来不对。 我确定这是因为Graphics2D.drawLine()Line2D.double()方法都无法以子像素精度绘制。

我知道我可以绘制来自中心的线条并用圆圈遮盖它(以创建更长,更准确的线条),但这似乎是一种不优雅且昂贵的解决方案。 我已经做过一些关于如何做到这一点的研究,但我遇到的最好的答案是使用AffineTransform 。 我假设我只能使用带旋转的AffineTransform ,而不必执行超级采样。

这是以亚像素精度绘制的唯一/最佳方法吗? 或者是否有更快的解决方案?

编辑 :我已经将RenderingHint设置为Graphics2D对象。

根据要求,这里有一些代码(没有完全优化,因为这只是一个PoC):

 diameter = Math.max(Math.min(pnlOuter.getSize().getWidth(), pnlOuter.getSize().getHeight()) - 2, MIN_DIAMETER); for (double radTick = 0d; radTick < 360d; radTick += 6d) { g2d.draw(new Line2D.Double( (diameter / 2) + (Math.cos(Math.toRadians(radTick))) * diameter / 2.1d, (diameter / 2) + (Math.sin(Math.toRadians(radTick))) * diameter / 2.1d, (diameter / 2) + (Math.cos(Math.toRadians(radTick))) * diameter / 2.05d, (diameter / 2) + (Math.sin(Math.toRadians(radTick))) * diameter / 2.05d)); } // End for(radTick) 

这是图纸的截图。 可能有点难以看到,但是看59分钟的刻度线。 它是完全垂直的。

样本图片

Line2D.double()方法无法以子像素精度绘制。

错误,使用RenderingHints.VALUE_STROKE_PURE ,Graphics2D对象可以使用形状Line2D绘制“子像素”精度。


我假设我只能使用带旋转的AffineTransform,而不必执行超级采样。 这是以亚像素精度绘制的唯一/最佳方法吗? 或者是否有更快的解决方案?

我想你在这里错过了什么。 Graphics2D对象已经拥有一个AffineTransform ,它正在将它用于所有绘图操作及其廉价的性能。


但是要回复你的代码中缺少的东西 – 这是缺失的:

 g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); 

下面是一个自包含的示例,生成此图片:

截图

 public static void main(String[] args) throws Exception { final JFrame frame = new JFrame("Test"); frame.add(new JComponent() { @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; System.out.println(g2d.getTransform()); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); double dia = Math.min(getWidth(), getHeight()) - 2; for (int i = 0; i < 60 ; i++) { double angle = 2 * Math.PI * i / 60; g2d.draw(new Line2D.Double( (dia / 2) + Math.cos(angle) * dia / 2.1d, (dia / 2) + Math.sin(angle) * dia / 2.1d, (dia / 2) + Math.cos(angle) * dia / 2.05d, (dia / 2) + Math.sin(angle) * dia / 2.05d)); } g2d.draw(new Ellipse2D.Double(1, 1, dia - 1, dia - 1)); } }); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(400, 400); frame.setVisible(true); }