9

我以前从未使用过 Java 绘图方法,因此我决定深入研究并创建一个模拟时钟作为 PoC。除了指针之外,我还绘制了一个包含分钟/小时刻度线的钟面。我使用简单的 sin/cos 计算来确定圆周围线条的位置。

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

我知道我可以画出从中心开始的线条并用一个圆圈将其遮住(以创建更长、更准确的线条),但这似乎是一个不雅且昂贵的解决方案。我已经对如何做到这一点进行了一些研究,但我遇到的最佳答案是使用AffineTransform. 我假设我只能使用AffineTransformwith 旋转,而不是必须执行超级采样。

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

编辑:我已经RenderingHintGraphics2D对象设置了 a 。

根据要求,这里有一些代码(没有完全优化,因为这只是一个 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 分钟的刻度线。它是完全垂直的。

示例图像

4

1 回答 1

8

Line2D.double() 方法不能以亚像素精度绘制。

错了,使用RenderingHints.VALUE_STROKE_PUREGraphics2D 对象可以用 shape 绘制“亚像素”精度Line2D


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

我认为你在这里遗漏了一些东西。Graphics2D 对象已经拥有 aAffineTransform并且它正在将它用于所有绘图操作及其廉价的性能。


但是要回复您的代码中缺少的内容 - 这是缺少的:

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);
}
于 2011-02-16T16:38:10.453 回答