Java - 子像素线精度是否需要AffineTransform? [英] Java - Does subpixel line accuracy require an AffineTransform?

查看:180
本文介绍了Java - 子像素线精度是否需要AffineTransform?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've never worked with Java drawing methods before, so I decided to dive in and create an analog clock as a PoC. In addition to the hands, I draw a clock face that includes tick marks for minutes/hours. I use simple sin/cos calculations to determine the position of the lines around the circle.

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

However, I've noticed that since the minute tick-marks are very short, the angle of the lines looks wrong. I'm certain this is because both Graphics2D.drawLine() and Line2D.double() methods cannot draw with subpixel accuracy.

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

I know I can draw lines originating from the center and masking it out with a circle (to create longer, more accurate lines), but that seems like such an inelegant and costly solution. I've done some research on how to do this, but the best answer I've come across is to use an AffineTransform. I assume I could use an AffineTransform with rotation only, as opposed to having to perform a supersampling.

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

Is this the only/best method of drawing with sub-pixel accuracy? Or is there a potentially faster solution?

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

Edit: I am already setting a RenderingHint to the Graphics2D object.

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

As requested, here is a little bit of the code (not fully optimized as this was just 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分钟的刻度线。这是完全垂直的。

Here's a screenshot of the drawing. It may be somewhat difficult to see, but look at the tick mark for 59 minutes. It is perfectly vertical.

推荐答案


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

Line2D.double() methods cannot draw with subpixel accuracy.

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


我假设我可以使用
仅限旋转的AffineTransform,因为
反对必须执行
超级采样。这是使用亚像素
精度绘制的唯一/最佳
方法吗?或者是否有一个潜在的
更快的解决方案?

I assume I could use an AffineTransform with rotation only, as opposed to having to perform a supersampling. Is this the only/best method of drawing with sub-pixel accuracy? Or is there a potentially faster solution?

我认为你在这里缺少一些东西。 Graphics2D对象已经拥有 AffineTransform ,它正在将它用于所有绘图操作及其廉价的性能。

I think you are missing somthing here. The Graphics2D object already holds a AffineTransform and it is using it for all drawing actions and its cheap performance wise.

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

But to get back to you what is missing from your code - this is missing:

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






以下是生成此图片的自包含示例:


Below is a self contained example that produces this picture:

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);
}

这篇关于Java - 子像素线精度是否需要AffineTransform?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆