Domanda

Ho provato con il metodo drawOval con uguale altezza e larghezza, ma come aumenta il diametro del cerchio diventa peggio guardando. Che cosa posso fare per avere un cerchio dall'aspetto decente non importa la dimensione. Come faccio a implementare l'anti-aliasing in java o qualche altro metodo.

È stato utile?

Soluzione

Come si è visto, Java2D (che sto assumendo è quello che si sta utilizzando) è già abbastanza bravo a questo! C'è un tutorial decente qui: http: //www.javaworld .com / JavaWorld / JW-08-1998 / JW-08-media.html

La linea è importante:

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

Altri suggerimenti

è possibile impostare il rendering suggerimenti:

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

Due cose che possono aiutare:

  1. Usa Graphics2D.draw(Shape) con un'istanza di java.awt.geom.Ellipse2D invece di Graphics.drawOval
  2. Se il risultato non è ancora soddisfacente, provare a utilizzare Graphics2D.setRenderingHint per abilitare l'antialiasing

Esempio

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

Si veda la risposta di Josef per un esempio di setRenderingHint

Naturalmente si imposta la distanza per ciò che mai è necessario:

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

Grazie a Oleg Estekhin per indicare la segnalazione di bug, perché spiega come farlo.

Ecco alcuni piccoli cerchi, prima e dopo. Ingrandita un paio di volte per vedere la griglia di pixel.

Circles prima e dopo

Scendendo di fila, si muovono un po 'di quantità subpixel.

La prima colonna è senza rendering suggerimenti. Il secondo è solo con antialias. Il terzo è con antialias e la modalità puro.

Si noti come con antialias solo suggerimenti, le prime tre cerchi sono gli stessi, e gli ultimi due sono anche lo stesso. Sembra che ci sia un po 'di transizione discreta accadendo. Probabilmente l'arrotondamento a un certo punto.

Ecco il codice. E 'in Jython per migliorare la leggibilità, ma guida la libreria di runtime Java sotto e può essere senza perdita di qualità portato su sorgente Java equivalente, con esattamente lo stesso effetto.

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"))

Sommario: è necessario sia VALUE_ANTIALIAS_ON e VALUE_STROKE_PURE per ottenere una corretta guardando i cerchi disegnati con precisione subpixel

.

L'incapacità di disegnare un "circolo aspetto decente" è legato al molto vecchio bug 6.431.487 .

Attivazione antialiasing su non aiuta molto - basta controllare il tipo di "cerchio" prodotto dalla drawOval () o drawShape (Eclipse) quando la dimensione del cerchio richiesto è di 16 pixel (ancora abbastanza comune per la dimensione delle icone) e antialiasing è sopra. Bigger cerchi antialias sarà un aspetto migliore, ma sono ancora asimmetrica, se qualcuno si cura di guardare da vicino.

Sembra che per disegnare un "circolo aspetto decente" si deve disegnare manualmente uno. Senza antialiasing sarà algoritmo cerchio punto medio (questo ha una risposta con un codice Java abbastanza per esso).

A CURA: 6 Settembre 2017

Questo è un algoritmo inventato da me per disegnare un cerchio su una matrice integer. La stessa idea potrebbe essere utilizzato per scrivere un cerchio all'interno di un BufferedImage. Se si sta tentando di disegnare quel cerchio utilizzando le classe Graphics non è questo l'Answare siete alla ricerca di (a meno che non si desidera modificare ogni colore-assegnazione con g.drawLine (x, y, x + 1, y), ma potrebbe essere molto lento).

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

Ho provato tante volte, verificando la correttezza manualmente, quindi penso che funzionerà. Non ho fatto alcuna gamma-assegno solo per semplificare il codice. Spero che vi aiuterà e tutti vogliono disegnare un cerchio su una matrice (ad esempio, quelli programmatore che cerca di creare i propri videogiochi sulla codice puro e la necessità di gestire un gioco-map matrix-oriented per memorizzare gli oggetti che si trovano sul gioco-map [se hai bisogno di aiuto su questo, mi e-mail]).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top