2009-07-07 21 views
22

He intentado utilizar el método drawOval con la misma altura y anchura, pero a medida que aumenta el diámetro, el círculo se vuelve peor. ¿Qué puedo hacer para tener un círculo de aspecto decente sin importar el tamaño? ¿Cómo implementaría anti-aliasing en Java o algún otro método?Cómo dibujar un Círculo de aspecto decente en Java

Respuesta

37

Como resultado, Java2D (que yo supongo que es lo que estás usando) ¡ya es bastante bueno en esto! Hay un tutorial decente aquí: http://www.javaworld.com/javaworld/jw-08-1998/jw-08-media.html

La línea importante es:

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

Tienes vínculos de amor de 11 años, la esperanza de que nunca morirán. –

+16

Parece que las constantes se han movido de Graphics2D a RenderingHints. Ver [este ejemplo] (http://www.java2s.com/Code/JavaAPI/java.awt/Graphics2DsetRenderingHintKeyhintKeyObjecthintValue.htm). –

+1

Tiene 17 años ahora ... sigue vivo xD lol – maganap

27

se pueden establecer consejos de renderizado:

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

Dos cosas que pueden ayudar:

  1. Uso Graphics2D.draw(Shape) con una instancia de java.awt.geom.Ellipse2D en lugar de Graphics.drawOval
  2. Si el resultado todavía no es satisfactoria, intente usar Graphics2D.setRenderingHint para habilitar el antialiasing

Ejemplo

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

Sede de Josef para un ejemplo de setRenderingHint

6

Por supuesto se establece su radio a lo que usted necesita:

@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

También es necesario ajustar la posición de la elipse, y creo que no desea g2d.draw g2d.stroke – finnw

3

Incapacidad para dibujar un "círculo de aspecto decente" está relacionada con la muy antigua fallo 6431487.

Activar el antialiasing no ayuda mucho - solo compruebe el tipo de "círculo" producido por drawOval() o drawShape (Eclipse) cuando el tamaño del círculo requerido es 16 píxeles (todavía bastante común para el tamaño del icono) y antialiasing Está encendido. Los círculos antialias más grandes se verán mejor, pero siguen siendo asimétricos, si alguien se preocupa por mirarlos de cerca.

Parece que para dibujar un "círculo de aspecto decente" hay que dibujar uno manualmente. Sin antialiasing será un algoritmo de círculo de punto medio (este question tiene una respuesta con un bonito código de java para él).

-1

Editado: 06 de septiembre de 2017

Eso es un algoritmo inventado por mí para dibujar un círculo sobre una matriz de enteros. La misma idea podría usarse para escribir un círculo dentro de una Imagen Buffered. Si está tratando de dibujar ese círculo con la clase Graphics, este no es el answare que está buscando (a menos que desee modificar cada asignación de color con g.drawLine (x, y, x + 1, y), pero podría ser muy 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; 
} 

Lo intenté muchas veces, verificando manualmente su corrección, así que creo que funcionará. No hice ningún control de rango solo para simplificar el código. Espero que te ayude a ti y a todos a dibujar un círculo sobre una matriz (por ejemplo, esos programadores que intentan crear sus propios videojuegos en código puro y necesitan administrar un mapa de juego orientado a la matriz para almacenar los objetos que están sobre el mapa del juego [si necesita ayuda sobre esto, envíeme un correo electrónico]).

3

Gracias a Oleg Estekhin por señalar el informe de fallos, porque explica cómo hacerlo.

Aquí hay algunos círculos pequeños antes y después. Magnificado algunas veces para ver la cuadrícula de píxeles.

Circles before and after

Bajando una fila, se están moviendo ligeramente por cantidades subpíxeles.

La primera columna no contiene sugerencias. El segundo es solo con antialias. El tercero es con antialias y modo puro.

Tenga en cuenta que solo con sugerencias antialias, los primeros tres círculos son iguales y los dos últimos también son iguales. Parece que está ocurriendo una transición discreta. Probablemente redondeando en algún punto.

Aquí está el código. Está en Jython para facilitar la lectura, pero controla la biblioteca de tiempo de ejecución de Java y puede ser portado sin pérdidas a una fuente Java equivalente, con exactamente el mismo efecto.

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

Resumen: Se necesitan las dos VALUE_ANTIALIAS_ON y VALUE_STROKE_PURE para obtener adecuado mirando los círculos dibujados con precisión de subpíxeles.

Cuestiones relacionadas