Java Graphics2D浮点精确drawOval替代?

所以我试图绘制一个圆弧并围绕其圆形端点放置一个圆圈,但由于四舍五入到最近的像素,我遇到了问题。 这在一些但不是所有情况下都可见。

有没有办法使用浮点和消除锯齿绘制圆圈以消除此舍入错误?

您可以运行此代码来查看问题。 为了清晰起见,我绘制了长度为0的弧(显示为大点)而不是全弧。

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

作为替代方案,请考虑使用具有合适RenderingHints Ellipse2D 。 此处显示了典型用法。

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

因为各种RenderingHints是依赖于实现的,所以下面的示例将让您单独评估效果。

图片

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