2016-07-29 4 views
2

Also ich versuche, einen Bogen zu zeichnen und einen Kreis um seinen runden Endpunkt zu legen, aber ich habe Probleme aufgrund der Rundung auf den nächsten Pixel. Dies ist in einigen, aber nicht allen Fällen sichtbar.Java Graphics2D Fließkomma-genaue ZeichnungOval Alternative?

Gibt es eine Möglichkeit, Kreise mit Gleitkomma und Anti-Aliasing zu zeichnen, um diesen Rundungsfehler zu eliminieren?

Sie können diesen Code ausführen, um das Problem zu sehen. Ich habe Bögen der Länge 0 gezeichnet (die als große Punkte erscheinen) anstelle von vollen Bögen zur Klarheit.

import java.awt.*; 
import javax.swing.*; 

public class Example extends JFrame { 

    private int CENTER = 200; 
    private static int WINDOW = 400; 

    private int LEFT = 50; 
    private int TOP = 50; 
    private int DIM = 300; 
    private int DIAMETER = 26; 

    public Example() { 
     super(); 
    } 

    public void paint (Graphics g) { 
     Graphics2D g2 = (Graphics2D) g; 

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

     g2.setStroke(new BasicStroke(16, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER)); 
     g2.setColor(new Color(0, 0, 255)); 

     g2.drawArc(LEFT, TOP, DIM, DIM, 0, 0); 
     g2.drawArc(LEFT, TOP, DIM, DIM, 32, 0); 
     g2.drawArc(LEFT, TOP, DIM, DIM, 115, 0); 
     g2.drawArc(LEFT, TOP, DIM, DIM, 200, 0); 
     g2.drawArc(LEFT, TOP, DIM, DIM, 331, 0); 

     this.drawCircle(g2, 0); 
     this.drawCircle(g2, 32); 
     this.drawCircle(g2, 115); 
     this.drawCircle(g2, 200); 
     this.drawCircle(g2, 331); 

     g2.setStroke(new BasicStroke(1)); 
     g2.setColor(new Color(0, 0, 0)); 
     g2.drawLine(0, CENTER, DIM * 2, CENTER); 
     g2.drawLine(CENTER, 0, CENTER, DIM * 2); 
    } 

    private void drawCircle(Graphics2D g, int angle) { 
     g.setStroke(new BasicStroke(3)); 
     g.setColor(new Color(0, 0, 255)); 
     g.drawOval(
      Math.round(CENTER + (float)(Math.cos(Math.toRadians(angle)) * (DIM/2)) - DIAMETER/2), 
      Math.round(CENTER - (float)(Math.sin(Math.toRadians(angle)) * (DIM/2)) - DIAMETER/2), 
      DIAMETER, 
      DIAMETER 
     ); 
    } 

    public static void main (String args[]) { 
     Example e = new Example(); 
     e.setSize(WINDOW, WINDOW); 
     e.setVisible(true); 
     e.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    } 
} 
+1

[ 'Ellipse2D'] (https://docs.oracle.com/javase/8/docs/api/java/awt/geom/Ellipse2D.html)? – trashgod

+0

Wenn Sie drei Quadrate in einer Reihe haben, haben Sie eine eindeutige Mitte - wenn Sie vier Quadrate in einer Reihe haben, haben Sie kein eindeutiges Zentrum - aber wenn Sie an Magie glauben, gehen Sie mit Antialiasing etc. voran – gpasch

+1

@trashgod Sie rocken. Das plus 'RenderingHints.VALUE_STROKE_PURE' hat alles perfekt aufgeräumt. Vielen Dank! – thedarklord47

Antwort

3

Als Alternative betrachten Ellipse2D mit geeigneten RenderingHints. Typische Verwendung ist here gezeigt.

Ellipse2D circle = new Ellipse2D.Float(…); 
Graphics2D g2d = (Graphics2D) g; 
g2d.setRenderingHints(…); 
g2d.fill(circle); 

Da verschiedene RenderingHints Implementierung abhängig sind, das folgende Beispiel lassen Sie die Effekte einzeln zu bewerten.

image

import java.awt.BasicStroke; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.RenderingHints; 
import java.awt.geom.Ellipse2D; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 

/** 
* @see https://stackoverflow.com/a/38669048/230513 
*/ 
public class Test { 

    private void display() { 
     JFrame f = new JFrame("Test"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.add(new JPanel() { 
      private static final int N = 8; 
      private final Ellipse2D ellipse = new Ellipse2D.Float(); 

      @Override 
      protected void paintComponent(Graphics g) { 
       super.paintComponent(g); 
       Graphics2D g2d = (Graphics2D) g; 
       g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
        RenderingHints.VALUE_ANTIALIAS_ON); 
       g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, 
        RenderingHints.VALUE_STROKE_PURE); 
       g2d.setStroke(new BasicStroke(N)); 
       ellipse.setFrame(N, N, getWidth() - 2 * N, getHeight() - 2 * N); 
       g2d.draw(ellipse); 
      } 

      @Override 
      public Dimension getPreferredSize() { 
       return new Dimension(320, 240); 
      } 
     }); 
     f.pack(); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Test()::display); 
    } 
} 
+0

perfekt. Danke. kann für zukünftige Benutzer wertvoll sein, wenn Sie tatsächlich die Rendering-Tipps geschrieben haben, die es am genauesten aussehen lassen. im Grunde nur 'VALUE_ANTIALIAS_ON' und' VALUE_STROKE_PURE' – thedarklord47

+0

@ thedarklord47: Guter Punkt; aktualisiert. – trashgod