Java Graphics drawArc with high precision

I am trying to draw a high precision arc in Java using AWT / Swing. The Graphics class offers the drawArc method for this, and in most cases this is normal. However, when the arc has a large radius (Ie The parameters "width" and "height" are large), then the arc will not be accurately drawn. This is because the parameters "startAngle" and "arcAngle" are set as integer degrees. I have to convert the angle (given in radians) to degrees, and then round it. Loss of accuracy causes the arc to not reach the actual end point (if you round it) or move further than it should (if you round up).

I am looking for an alternative method of drawing arcs. Preferably, this should work the same, but take floating point angles as parameters.

If such a function does not exist (I could not find it), I would like to write it myself, but I have no idea how to do this, since the Graphics class already offers the lowest level drawing methods I can find. The only idea I had was to approximate an arc with a sequence of straight lines, but you need a lot of lines to get a smooth arc, and it seems terribly inefficient.

+4
source share
2 answers

If you want to use double values ​​for your angle options, why not use an Arc2D object like Arc2D.Double ? All parameters you specify are double type.

Also, are you setting the RenderingHints object correctly for the Graphics2D object to prevent anti-aliasing?

eg,

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(); } }); } } 
+5
source

Using Graphics2D, you can use the rotate (theta, x, y) function to accurately draw one end of your arc:

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

Then you just need to accurately draw the last bit on the other side:

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

And you will have one arc drawn for exact theta values. This is probably not the most efficient way to do this, in a machine-made way, due to the partial overlap of the redraw; but this is the easiest way to do this that I can think of.

+1
source

All Articles