2011-02-16 8 views
8

Nunca antes había trabajado con los métodos de dibujo de Java, así que decidí bucear y crear un reloj analógico como PoC. Además de las manos, dibujo un reloj que incluye marcas por minutos/horas. Utilizo cálculos simples de sin/cos para determinar la posición de las líneas alrededor del círculo.Java: ¿la precisión de línea de subpixel requiere un AffineTransform?

Sin embargo, he notado que desde el minuto en que las marcas son muy cortas, el ángulo de las líneas parece incorrecto. Estoy seguro de que esto se debe a que los métodos Graphics2D.drawLine() y Line2D.double() no se pueden dibujar con precisión subpíxel.

Sé que puedo dibujar líneas que se originan en el centro y enmascararlas con un círculo (para crear líneas más largas y precisas), pero parece una solución tan poco elegante y costosa. Hice algunas investigaciones sobre cómo hacer esto, pero la mejor respuesta que he encontrado es usar un AffineTransform. Supongo que podría usar un AffineTransform solo con rotación, en lugar de tener que realizar un supermuestreo.

¿Es este el único/mejor método de dibujo con precisión subpíxel? ¿O hay una solución potencialmente más rápida?

Editar: Ya estoy estableciendo un RenderingHint al objeto Graphics2D.

a lo solicitado, aquí es un poco de código (no completamente optimizado ya que esto era sólo una PoC):

diameter = Math.max(Math.min(pnlOuter.getSize().getWidth(), 
          pnlOuter.getSize().getHeight()) - 2, MIN_DIAMETER); 

for (double radTick = 0d; radTick < 360d; radTick += 6d) { 
    g2d.draw(new Line2D.Double(
     (diameter/2) + (Math.cos(Math.toRadians(radTick))) * diameter/2.1d, 
     (diameter/2) + (Math.sin(Math.toRadians(radTick))) * diameter/2.1d, 
     (diameter/2) + (Math.cos(Math.toRadians(radTick))) * diameter/2.05d, 
     (diameter/2) + (Math.sin(Math.toRadians(radTick))) * diameter/2.05d)); 
} // End for(radTick) 

Aquí hay una captura de pantalla del dibujo. Puede ser algo difícil de ver, pero mira la marca durante 59 minutos. Es perfectamente vertical.

Sample image

+0

sc una nueva visión del reloj y el código para calcular/dibujar el reloj ayudaría. –

Respuesta

8

Line2D.double() métodos no pueden dibujar con una precisión de subpíxel.

incorrecto, utilizando RenderingHints.VALUE_STROKE_PURE el objeto Graphics2D puede dibujar exactitud "subpixel" con la forma Line2D.


Asumo que podría utilizar un AffineTransform sólo con rotación, como lugar de tener que realizar una supersampling . ¿Es este el único/mejor método de dibujo con una precisión de subpíxel? ¿O existe una solución potencialmente más rápida ?

Creo que se está perdiendo algo aquí. El objeto Graphics2D ya tiene un AffineTransform y lo está usando para todas las acciones de dibujo y su rendimiento económico.


Pero para llegar de nuevo a usted lo que falta en su código - esto es que falta:

g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, 
        RenderingHints.VALUE_STROKE_PURE); 

A continuación se muestra una auto ejemplo que produce esta imagen contenía:

screenshot

public static void main(String[] args) throws Exception { 

    final JFrame frame = new JFrame("Test"); 

    frame.add(new JComponent() { 
     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 

      Graphics2D g2d = (Graphics2D) g; 

      System.out.println(g2d.getTransform()); 
      g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
           RenderingHints.VALUE_ANTIALIAS_ON); 
      g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, 
           RenderingHints.VALUE_STROKE_PURE); 

      double dia = Math.min(getWidth(), getHeight()) - 2; 

      for (int i = 0; i < 60 ; i++) { 
       double angle = 2 * Math.PI * i/60; 
       g2d.draw(new Line2D.Double(
         (dia/2) + Math.cos(angle) * dia/2.1d, 
         (dia/2) + Math.sin(angle) * dia/2.1d, 
         (dia/2) + Math.cos(angle) * dia/2.05d, 
         (dia/2) + Math.sin(angle) * dia/2.05d)); 
      } 

      g2d.draw(new Ellipse2D.Double(1, 1, dia - 1, dia - 1)); 
     } 
    }); 

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.setSize(400, 400); 
    frame.setVisible(true); 
} 
+0

Hmm, parece que está utilizando una 'AffineTransform' que * does * tiene que traducir (es decir, supersample), así como rotar. Espero evitar esto, ya que actualmente tengo esta actualización cada 50 ms. –

+0

¿No debería dibujar la esfera del reloj por separado y luego fusionarla con las manecillas del reloj cambiantes? –

+0

@ D.N .: ¿Solo estoy creando la imagen sin conexión * una vez *? ¿Necesita crearlo en cada actualización? (@ typo.pl: yes) – dacwe

Cuestiones relacionadas