5

I'm trying to draw a high precision arc in Java using AWT/Swing. The Graphics class offers the "drawArc" method to do this and in most cases this is fine. However, when the arc has a large radius (I.e. The "width" and "height" parameters are large) then the arc will not be drawn precisely. This is because the "startAngle" and "arcAngle" parameters are given as integer degrees. I'm forced to convert an angle (given in radians) to degrees and then rounding it. The loss of precision leads to the arc falling short of its actual end point (if you round down) or go further than it should (if you round up).

I'm looking for an alternative method of drawing arcs. Preferable this should work in the same way but accept floating point angles as parameters.

If such a function does not exist (I've not been able to find one) I would like to write it myself, but I have no idea how to go about this as the Graphics class already offers the lowest level drawing methods I can find. The only idea I had is to approximate the arc with a sequence of straight lines but to get a smooth arc you would need a lot of lines and this seems dreadfully inefficient.

4

2 回答 2

6

如果您希望对角度参数使用双精度值,为什么不使用Arc2D对象,例如Arc2D.Double呢?您提到的所有参数都是双重类型。

另外,您是否正确设置了 Graphics2D 对象的 RenderingHints 以允许抗锯齿?

例如,

import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.geom.Arc2D;

import javax.swing.*;

@SuppressWarnings("serial")
public class TestArc2D extends JPanel {
   private static final int PREF_W = 1000;
   private static final int PREF_H = 400;
   private static final Stroke STROKE = new BasicStroke(5f);
   private static final Color ARC_COLOR = Color.red;
   private Arc2D arc;

   public TestArc2D() {
      addComponentListener(new ComponentAdapter() {
         @Override
         public void componentResized(ComponentEvent e) {
            double x = 10;
            double y = x;
            double w = getWidth() - 2 * x;
            double h = 2 * getHeight() - 2 * y - 50;
            double start = 0;
            double extent = 180.0;
            arc = new Arc2D.Double(x, y, w, h, start , extent, Arc2D.OPEN);
         }
      });
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      Graphics2D g2 = (Graphics2D) g.create();
      g2.setStroke(STROKE);
      g2.setColor(ARC_COLOR);
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
      if (arc != null) {
         g2.draw(arc);
      }
      g2.dispose();
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_W, PREF_H);
   }

   private static void createAndShowGui() {
      TestArc2D mainPanel = new TestArc2D();

      JFrame frame = new JFrame("TestArc2D");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}
于 2013-02-02T20:18:24.760 回答
1

使用 Graphics2D,您可以使用 rotate(theta,x,y) 函数精确绘制弧线的一端:

g2.rotate(-1*thetaStartRadians,xc,yc);
g2.drawArc(x1,y1,width,height,0, thetaLengthDegrees-1);
g2.rotate(thetaStartRadians,xc,yc);

然后你只需要精确地画出另一边的最后一点:

g2.rotate(-1*thetaLengthRadians,xc,yc);
g2.drawArc(x1,y1,width,height,0,-2));
g2.rotate(thetaLengthRadians,xc,yc);

并且您将绘制一条弧线以精确的 theta 值。在机器方面,这可能不是最有效的方法,因为有一点重绘重叠;但这是我能想到的最简单的方法。

于 2017-12-07T19:03:10.987 回答