【问题标题】:How to draw a decent looking Circle in Java如何在 Java 中绘制一个看起来像样的圆圈
【发布时间】:2010-11-08 20:02:37
【问题描述】:

我尝试过使用具有相同高度和宽度的 drawOval 方法,但随着直径的增加,圆的外观变得更糟。无论大小,我该怎么做才能拥有一个体面的圆圈。我将如何在 java 或其他方法中实现抗锯齿。

【问题讨论】:

    标签: java graphics antialiasing geometry


    【解决方案1】:

    事实证明,Java2D(我假设是您正在使用的)在这方面已经相当出色了!这里有一个不错的教程:http://www.javaworld.com/javaworld/jw-08-1998/jw-08-media.html

    重要的一行是:

    graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                              RenderingHints.VALUE_ANTIALIAS_ON);
    

    【讨论】:

    • 你必须爱上 11 岁的链接,希望它们永远不会死。
    • 看起来常量已从 Graphics2D 移至 RenderingHints。见this example
    • 19 年了,还在数=P
    • 20 还活着! :ㅇ
    • 不。找不到页面
    【解决方案2】:

    您可以设置渲染提示:

    Graphics2D g2 = (Graphics2D) g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
    

    【讨论】:

      【解决方案3】:

      两件事可能会有所帮助:

      1. Graphics2D.draw(Shape)java.awt.geom.Ellipse2D 的实例一起使用,而不是Graphics.drawOval
      2. 如果效果仍然不理想,请尝试使用Graphics2D.setRenderingHint 启用抗锯齿

      例子

      public void paint(Graphics g) {
          Graphics2D g2d = (Graphics2D) g;
          Shape theCircle = new Ellipse2D.Double(centerX - radius, centerY - radius, 2.0 * radius, 2.0 * radius);
          g2d.draw(theCircle);
      }
      

      有关setRenderingHint 的示例,请参见 Josef 的回答

      【讨论】:

        【解决方案4】:

        当然,您可以根据需要设置半径:

        @Override
        public void paint(Graphics g) {
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            Ellipse2D.Double hole = new Ellipse2D.Double();
            hole.width = 28;
            hole.height = 28;
            hole.x = 14;
            hole.y = 14;
            g2d.draw(hole);
        }
        

        【讨论】:

        • 你还需要设置椭圆的位置,我想你想要的是 g2d.draw 而不是 g2d.stroke
        【解决方案5】:

        感谢 Oleg Estekhin 指出错误报告,因为它解释了如何去做。

        这里有一些前后的小圆圈。放大几倍可以看到像素网格。

        向下移动,它们会稍微移动亚像素量。

        第一列没有渲染提示。第二个是仅使用抗锯齿。第三个是抗锯齿和纯模式。

        请注意如何仅使用抗锯齿提示,前三个圆圈相同,后两个圆圈也相同。似乎发生了一些离散的过渡。可能在某个时候四舍五入。

        这是代码。它在 Jython 中是为了便于阅读,但它驱动底层的 Java 运行时库,并且可以无损地移植到等效的 Java 源代码中,效果完全相同。

        from java.lang import *
        from java.io import *
        from java.awt import *
        from java.awt.geom import *
        from java.awt.image import *
        from javax.imageio import *
        
        bim = BufferedImage(30, 42, BufferedImage.TYPE_INT_ARGB)
        g = bim.createGraphics()
        g.fillRect(0, 0, 100, 100)
        g.setColor(Color.BLACK)
        for i in range(5):
            g.draw(Ellipse2D.Double(2+0.2*i, 2+8.2*i, 5, 5))
        
        g.setRenderingHint( RenderingHints.  KEY_ANTIALIASING,
                            RenderingHints.VALUE_ANTIALIAS_ON)
        
        for i in range(5):
            g.draw(Ellipse2D.Double(12+0.2*i, 2+8.2*i, 5, 5))
        
        g.setRenderingHint( RenderingHints.  KEY_STROKE_CONTROL,
                            RenderingHints.VALUE_STROKE_PURE)
        
        for i in range(5):
            g.draw(Ellipse2D.Double(22+0.2*i, 2+8.2*i, 5, 5))
        
        #You'll probably want this too later on:
        #g.setRenderingHint( RenderingHints.  KEY_INTERPOLATION,
        #                    RenderingHints.VALUE_INTERPOLATION_BICUBIC)
        #g.setRenderingHint( RenderingHints.  KEY_RENDERING, 
        #                    RenderingHints.VALUE_RENDER_QUALITY)
        
        ImageIO.write(bim, "PNG", File("test.png"))
        

        总结:您需要VALUE_ANTIALIAS_ONVALUE_STROKE_PURE 才能以亚像素精度绘制外观正确的圆圈。

        【讨论】:

          【解决方案6】:

          无法画出“看起来像样的圆圈”与非常古老的错误6431487有关。

          打开抗锯齿并没有多大帮助 - 只需检查 drawOval() 或 drawShape(Eclipse) 产生的“圆形”类型,当所需的圆形大小为 16 像素(对于图标大小仍然很常见)并且抗锯齿是在。更大的抗锯齿圆看起来会更好,但它们仍然是不对称的,如果有人愿意仔细观察的话。

          似乎要绘制一个“看起来不错的圆圈”,必须手动绘制一个。如果没有抗锯齿,它将是中点圆算法(这个question 有一个漂亮的java代码的答案)。

          【讨论】:

            【解决方案7】:

            编辑:2017 年 9 月 6 日

            这是我发明的一种算法,用于在整数矩阵上画一个圆。可以使用相同的想法在 BufferedImage 中写入一个圆圈。 如果您尝试使用 Graphics 类绘制该圆,这不是您正在寻找的答案(除非您希望使用 g.drawLine(x, y, x+1, y) 修改每个颜色分配,但它可以非常慢)。

            protected boolean runOnCircumference(int[][] matrix, int x, int y, int ray, int color) {
                boolean ret;
                int[] rowUpper = null, rowInferior = null, rowCenterUpper = null, rowCenterInferior = null;
            
                if (ret = ray > 0) {
                    if (ray == 1) {
                        matrix[y][x + 1] = color;
                        rowUpper = matrix[++y];
                        rowUpper[x] = color;
                        rowUpper[x + 2] = color;
                        matrix[y][x] = color;
                    } else {
                        double rRay = ray + 0.5;
                        int r = 0, c = 0, ray2 = ray << 1, ray_1 = ray - 1, halfRay = (ray >> 1) + ray % 2, rInf,
                                ray1 = ray + 1, horizontalSymmetricOldC;
                        // draw cardinal points
            
                        rowUpper = matrix[ray + y];
                        rowUpper[x] = color;
                        rowUpper[x + ray2] = color;
                        matrix[y][x + ray] = color;
                        matrix[ray2 + y][x + ray] = color;
            
                        horizontalSymmetricOldC = ray1;
                        rInf = ray2;
                        c = ray_1;
                        for (r = 0; r < halfRay; r++, rInf--) {
            
                            rowUpper = matrix[r + y];
                            rowInferior = matrix[rInf + y];
            
                            while (c > 0 && (Math.hypot(ray - c, (ray - r)) < rRay)) {
            
                                rowUpper[x + c] = color;
                                rowUpper[x + horizontalSymmetricOldC] = color;
                                rowInferior[x + c] = color;
                                rowInferior[x + horizontalSymmetricOldC] = color;
            
                                // get the row pointer to optimize
                                rowCenterUpper = matrix[c + y];
                                rowCenterInferior = matrix[horizontalSymmetricOldC + y];
                                // draw
                                rowCenterUpper[x + r] = color;
                                rowCenterUpper[x + rInf] = color;
                                rowCenterInferior[x + r] = color;
                                rowCenterInferior[x + rInf] = color;
                                horizontalSymmetricOldC++;
                                c--;
                            }
                        } // end r circle
                    }
                }
                return ret;
            }
            

            我尝试了很多次,手动验证它的正确性,所以我认为它会起作用。我没有进行任何范围检查只是为了简化代码。 我希望它能帮助你和每个希望在矩阵上画一个圆圈的人(例如,那些试图在纯代码上创建自己的视频游戏并且需要管理面向矩阵的游戏地图来存储位于矩阵上的对象的程序员)游戏地图 [如果您需要这方面的帮助,请给我发电子邮件])。

            【讨论】:

              猜你喜欢
              • 2020-05-22
              • 2021-10-20
              • 2021-06-21
              • 1970-01-01
              • 2015-10-20
              • 2013-12-02
              • 1970-01-01
              • 1970-01-01
              • 2012-12-02
              相关资源
              最近更新 更多