2013-02-02 78 views
4

我想用AWT/Swing在Java中绘制高精度弧。 Graphics类提供了“drawArc”方法来做到这一点,在大多数情况下,这是很好的。但是,当圆弧半径较大时(即“宽度”和“高度”参数较大),则不会精确绘制圆弧。这是因为“startAngle”和“arcAngle”参数是以整数度量给出的。我不得不将角度(以弧度给出)转换为度数,然后将其舍入。精度的损失会导致电弧低于其实际终点(如果向下取整)或超出其应有的距离(如果向上取整)。Java图形高精度drawArc

我正在寻找绘制弧线的替代方法。最好这应该以相同的方式工作,但接受浮点角度作为参数。

如果这样的函数不存在(我还没有找到)我想自己写,但我不知道如何去做,因为Graphics类已经提供了最低级别的绘图我可以找到的方法。我唯一的想法是用一系列直线逼近弧线,但为了得到平滑的弧线,您需要很多线条,这看起来非常低效。

回答

5

如果您希望为角度参数使用双精度值,为什么不使用对象,如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(); 
     } 
     }); 
    } 
} 
+0

请注意,我在paintComponent方法中创建了一个新的Graphics对象,因此我可以设置其笔画而不必担心副作用。另一种方法是存储旧的Stroke值,设置新的值,使用它,然后重新将图形描边字段设置为其原始值。 –

1

使用的Graphics2D,可以使用旋转(θ表示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值。这可能不是最有效的方式,机器方式,因为重绘的部分重叠;但这是我能想到的最简单的方法。