代码之家  ›  专栏  ›  技术社区  ›  Bobby

如何在Java中画出一个好看的圆圈

  •  23
  • Bobby  · 技术社区  · 16 年前

    我试过用同样高度和宽度的方法画椭圆,但是随着直径的增加,圆的外观会变差。我能做什么才能有一个体面的环型,无论大小。如何在Java或其他方法中实现反走样。

    7 回复  |  直到 8 年前
        1
  •  40
  •   NESPowerGlove    10 年前

    事实证明,java2d(我假设这是您正在使用的)已经非常擅长这个了!这里有一个不错的教程: http://www.javaworld.com/javaworld/jw-08-1998/jw-08-media.html

    重要的是:

    graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                              RenderingHints.VALUE_ANTIALIAS_ON);
    
        2
  •  28
  •   Josef Pfleger    16 年前

    可以设置渲染提示:

    Graphics2D g2 = (Graphics2D) g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
    
        3
  •  12
  •   finnw    12 年前

    有两件事可能会有所帮助:

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

    参见Josef的答案以了解 setRenderingHint

        4
  •  6
  •   I82Much    13 年前

    当然,你可以将半径设置为你需要的半径:

    @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);
    }
    
        5
  •  4
  •   Martijn Courteaux    10 年前

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

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

    Circles before and after

    沿着一行往下看,它们以亚像素的数量轻微移动。

    第一列没有呈现提示。第二种是抗过敏药。第三种是抗锯齿和纯模式。

    请注意,仅使用反锯齿提示时,前三个圆是相同的,后两个圆也是相同的。似乎有一些离散的转变正在发生。可能在某一点上是四舍五入的。

    这是密码。它在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_ON VALUE_STROKE_PURE 以亚像素精度绘制合适的观察圆。

        6
  •  3
  •   Community CDub    8 年前

    无法画出一个“好看的圆圈”与这个老错误有关。 6431487 .

    打开抗锯齿并没有太大帮助-只需检查drawoval()或drawshape(eclipse)生成的“圆”的类型,当所需的圆大小为16像素(对于图标大小来说仍然很常见)并且抗锯齿处于打开状态时。如果有人愿意仔细观察的话,较大的反锯齿圆看起来会更好,但它们仍然是不对称的。

    看来要画一个“好看的圆圈”就得用手画一个。如果不进行抗锯齿,则将是中点圆算法(此 question 有一个漂亮的Java代码的答案。

        7
  •  -1
  •   Marco Ottina    8 年前

    编辑:2017年9月6日

    这是我发明的在整数矩阵上画圆的算法。同样的想法也可以用于在BufferedImage中编写一个圆。 如果您试图使用类图形绘制圆,则这不是您要查找的Answare(除非您希望使用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;
    }
    

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