How to draw a decent looking Circle in Java

前端 未结 7 1350
我在风中等你
我在风中等你 2020-11-27 06:20

I have tried using the method drawOval with equal height and width but as the diameter increases the circle becomes worse looking. What can I do to have a decent looking cir

相关标签:
7条回答
  • 2020-11-27 06:39

    Inability to draw a "decent looking circle" is related to the very old bug 6431487.

    Turning antialiasing on does not help a lot - just check the kind of "circle" produced by the drawOval() or drawShape(Eclipse) when the required circle size is 16 pixels (still pretty common for icon size) and antialiasing is on. Bigger antialiased circles will look better but they are still asymmetric, if somebody will care to look at them closely.

    It seems that to draw a "decent looking circle" one has to manually draw one. Without antialiasing it will be midpoint circle algorithm (this question has an answer with a pretty java code for it).

    0 讨论(0)
  • 2020-11-27 06:45

    Two things that may help:

    1. Use Graphics2D.draw(Shape) with an instance of java.awt.geom.Ellipse2D instead of Graphics.drawOval
    2. If the result is still not satisfactory, try using Graphics2D.setRenderingHint to enable antialiasing

    Example

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

    See Josef's answer for an example of setRenderingHint

    0 讨论(0)
  • 2020-11-27 06:47

    you can set rendering hints:

    Graphics2D g2 = (Graphics2D) g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
    
    0 讨论(0)
  • 2020-11-27 06:49

    EDITED: 06 September 2017

    That's an algorithm invented by me to draw a circle over a integer matrix. The same idea could be used to write a circle inside a BufferedImage. If you are trying to draw that circle using the class Graphics this is not the answare you are looking for (unless you wish to modify each color-assignement with g.drawLine(x, y, x+1, y), but it could be very slow).

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

    I tried it so many times, verifying manually it correctness, so I think it will work. I haven't made any range-check just to simplify the code. I hope it will help you and everyone wish to draw a circle over a matrix (for example, those programmer who tries to create their own videogames on pure code and need to manage a matrix-oriented game-map to store the objects lying on the game-map [if you need help on this, email me]).

    0 讨论(0)
  • 2020-11-27 06:51

    As it turns out, Java2D (which I'm assuming is what you're using) is already pretty good at this! There's a decent tutorial here: http://www.javaworld.com/javaworld/jw-08-1998/jw-08-media.html

    The important line is:

    graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                              RenderingHints.VALUE_ANTIALIAS_ON);
    
    0 讨论(0)
  • 2020-11-27 06:54

    Of course you set your radius to what ever you need:

    @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);
    }
    
    0 讨论(0)
提交回复
热议问题