2011-02-16 35 views
8

我之前從未使用過Java繪圖方法,因此我決定潛入並創建一個模擬時鐘作爲PoC。除了手之外,我還繪製了一個包含刻度線的鐘面,分鐘/小時。我使用簡單的正弦/餘弦計算來確定圓周線的位置。Java - 子像素行精度是否需要AffineTransform?

但是,我注意到,由於分鐘刻度非常短,線條的角度看起來不正確。我確定這是因爲Graphics2D.drawLine()Line2D.double()方法不能繪製子像素精度。

我知道我可以畫出源於中心的線條並用圓圈掩蓋它(以創建更長,更精確的線條),但是這看起來像是一種不雅和昂貴的解決方案。我已經做了一些研究,如何做到這一點,但我遇到的最好的答案是使用AffineTransform。我假設我可以只用旋轉AffineTransform,而不必執行超級取樣。

這是用亞像素精度繪製的唯一/最好的方法嗎?還是有一個可能更快的解決方案?

編輯:我已經設置RenderingHintGraphics2D對象。

按照要求,這裏是代碼的一點點(沒有完全優化,因爲這只是一個POC):

diameter = Math.max(Math.min(pnlOuter.getSize().getWidth(), 
          pnlOuter.getSize().getHeight()) - 2, MIN_DIAMETER); 

for (double radTick = 0d; radTick < 360d; radTick += 6d) { 
    g2d.draw(new Line2D.Double(
     (diameter/2) + (Math.cos(Math.toRadians(radTick))) * diameter/2.1d, 
     (diameter/2) + (Math.sin(Math.toRadians(radTick))) * diameter/2.1d, 
     (diameter/2) + (Math.cos(Math.toRadians(radTick))) * diameter/2.05d, 
     (diameter/2) + (Math.sin(Math.toRadians(radTick))) * diameter/2.05d)); 
} // End for(radTick) 

這裏有圖紙的截屏。看起來可能有些困難,但請看59分鐘的刻度線。這是完美的垂直。

Sample image

+0

sc時鐘和計算/繪製時鐘的代碼的恢復將有所幫助。 –

回答

8

Line2D.double()方法不能與亞像素精度繪製 。

錯誤的,使用RenderingHints.VALUE_STROKE_PURE Graphics2D對象可以繪製形狀爲Line2D的「子像素」精度。


我假設我可以使用一個 的AffineTransform僅具有旋轉的,如 反對不必執行 超級採樣。這是唯一的/最好的 方法的子像素 繪圖的準確性?或者有更快的解決方案嗎?

我想你是在這裏失蹤的東西。 Graphics2D對象已經擁有AffineTransform,並且它正在使用它來製作全部動作及其低廉的性能表現。


但要回你的是從你的代碼失蹤 - 這是缺少:

g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, 
        RenderingHints.VALUE_STROKE_PURE); 

下面是一個自包含的例子產生這樣的畫面:

screenshot

public static void main(String[] args) throws Exception { 

    final JFrame frame = new JFrame("Test"); 

    frame.add(new JComponent() { 
     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 

      Graphics2D g2d = (Graphics2D) g; 

      System.out.println(g2d.getTransform()); 
      g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
           RenderingHints.VALUE_ANTIALIAS_ON); 
      g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, 
           RenderingHints.VALUE_STROKE_PURE); 

      double dia = Math.min(getWidth(), getHeight()) - 2; 

      for (int i = 0; i < 60 ; i++) { 
       double angle = 2 * Math.PI * i/60; 
       g2d.draw(new Line2D.Double(
         (dia/2) + Math.cos(angle) * dia/2.1d, 
         (dia/2) + Math.sin(angle) * dia/2.1d, 
         (dia/2) + Math.cos(angle) * dia/2.05d, 
         (dia/2) + Math.sin(angle) * dia/2.05d)); 
      } 

      g2d.draw(new Ellipse2D.Double(1, 1, dia - 1, dia - 1)); 
     } 
    }); 

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.setSize(400, 400); 
    frame.setVisible(true); 
} 
+0

嗯,看起來你正在使用* AffineTransform',它不得不翻譯(即超級採樣)以及旋轉。我希望避免這種情況,因爲我目前每50ms更新一次。 –

+0

不應該分別繪製時鐘表面,然後將其與變化的鐘針一起合併? –

+0

@ D.N .:我只創建一次*離線圖像*?你需要每一次更新創建它嗎? (@ typo.pl:是) – dacwe