Вопрос по graphics, java, circle, antialiasing – Как нарисовать достойно выглядящий круг на Java

23

Я попытался использовать метод drawOval с равными высотой и шириной, но с увеличением диаметра круг становится хуже. Что я могу сделать, чтобы иметь прилично выглядящий круг независимо от размера. Как бы я реализовать сглаживание в Java или какой-то другой метод.

Ваш Ответ

7   ответов
28

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

Конечно, вы устанавливаете свой радиус на то, что вам нужно:

@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
12

Две вещи, которые могут помочь:

  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

пример

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

3

Невозможность нарисовать «прилично выглядящий круг» связано с очень старой ошибкой6431487.

Включение сглаживания не очень помогает - просто отметьте вид "круга" производится drawOval () или drawShape (Eclipse), когда требуемый размер круга равен 16 пикселям (все еще довольно часто встречается для размера значка), и сглаживание включено. Большие сглаженные круги будут выглядеть лучше, но они все еще асимметричны, если кто-то захочет взглянуть на них поближе.

Кажется, что нарисовать «прилично выглядящий круг» нужно рисовать вручную. Без сглаживания это будет алгоритм окружности средней точки (этовопрос есть ответ с красивым кодом Java для этого).

4

Спасибо Олегу Эстехину за то, что он указал на отчет об ошибке, потому что он объясняет, как это сделать.

Вот несколько маленьких кружков до и после. Увеличено несколько раз, чтобы увидеть пиксельную сетку.

Circles before and after

Спускаясь вниз по строке, они слегка сдвигаются на субпиксельные величины.

Первый столбец без подсказок рендеринга. Второй только с противоядием. Третий - с антиалиасом и чистым режимом.

Обратите внимание, что только с подсказками antialias первые три круга одинаковы, а последние два также одинаковы. Кажется, что происходит некоторый дискретный переход. Вероятно, округление в какой-то момент.

Вот код. Он находится в 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 чтобы получить правильно выглядящие круги, нарисованные с точностью до субпикселя.

-1

ИЗДАНИЕ: 06 сентября 2017 г.

Это изобретенный мной алгоритм для рисования круга над целочисленной матрицей. Эта же идея может быть использована для написания круга внутри 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;
}

Я пробовал так много раз, проверяя вручную правильность, так что я думаю, что это будет работать. Я не делал никаких проверок диапазона просто для упрощения кода. Я надеюсь, что это поможет вам и всем, кто хочет нарисовать круг над матрицей (например, те программисты, которые пытаются создавать свои собственные видеоигры на чистом коде и которым нужно управлять матрично-ориентированной игровой картой для хранения объектов, лежащих на game-map [если вам нужна помощь, напишите мне]).

40

Как выясняется, Java2D (который, как я предполагаю, является тем, что вы используете) уже достаточно хорош в этом! Здесь приличное руководство:http://www.javaworld.com/javaworld/jw-08-1998/jw-08-media.html

Важная строка:

graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                          RenderingHints.VALUE_ANTIALIAS_ON);
Похоже, что константы были перемещены из Graphics2D в RenderingHints. Увидетьthis example.
Ты должен любить ссылки 11 лет, надеюсь, они никогда не умрут.
Сейчас ему 17 лет ... еще жив xD lol
20 и до сих пор живет! : & # X3147;
19 лет и до сих пор считаю = P

Похожие вопросы