2013-03-23 27 views
1

這個問題是一個後續到一個我問前段時間: Drawing a bordered path with sharp corners in Java的Java Swing的BasicStroke「帽」並不適用於零度角

實驗之後,我發現了一些行爲,可以預期,或可能是一個錯誤,但任何方式都不是我想要的。 SSCCE:

import java.awt.BasicStroke; 
import java.awt.Color; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.RenderingHints; 
import java.awt.geom.GeneralPath; 

import javax.swing.JFrame; 
import javax.swing.JPanel; 

public class CornerTest { 
    private JFrame frame; 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 
      public void run() { 
       try { 
        CornerTest window = new CornerTest(); 
        window.frame.setVisible(true); 
       } catch (Exception e) { 
        e.printStackTrace(); 
       } 
      } 
     }); 
    } 

    public CornerTest() { 
     initialize(); 
    } 

    private void initialize() { 
     frame = new JFrame(); 
     frame.setBounds(100, 100, 450, 300); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     JPanel panel = new JPanel() { 
      protected void paintComponent(Graphics g) { 
       GeneralPath path; 
       Graphics2D g2d = (Graphics2D) g; 
       g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
         RenderingHints.VALUE_ANTIALIAS_ON); 
       g2d.setStroke(new BasicStroke(15.5f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); 
       g2d.setColor(Color.BLACK); 
       path = new GeneralPath(); 
       path.moveTo(100, 100); 
       path.lineTo(200, 100); 
       path.lineTo(100, 50); 
       g2d.draw(path); 
      } 
     }; 
     frame.setBackground(Color.CYAN); 
     frame.add(panel); 
    } 
} 

通過採取線path.lineTo(100, 50);並與第二個參數玩,我們可以改變繪製的路徑的角度。有關各種示例,請參閱下面的圖像。

enter image description here

基本上,我繪製GeneralPath與角度每個圖像中略有下降。最終(在底部圖像中)角度達到零。在這種情況下,圓形的「連接」不再被繪製。這種說法很有道理,但有點不對。我不確定它是否有意。有趣的是,如果你改變了角度稍微大於0(通過改變以上path.lineTo(100, 99.999);引用的行圓角被再次吸入即

在我的應用程序是可能的路徑原路折回對自己(即創建零度角度),在這種情況下,在這種情況下,在審美上吸引更多的參與者。是否有任何方法可以破解Java源代碼以使其發揮作用?

回答

2

我畫很長的路徑與500+一樣的點,它會大量的開銷添加到我的paint方法來檢查每個「子路徑」

不要建的GeneralPath在塗料方法。你可以使用一個包裝類來過濾每個點,因爲它被添加。這裏的代碼將比較每次要添加點時線的斜率。當斜率相同時,在添加lineTo之前爲最後一點生成moveTo。這將導致生成圓形行程:

import java.awt.*; 
import java.awt.Color; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.RenderingHints; 
import java.awt.geom.*; 
import java.util.List; 
import java.util.ArrayList; 

import javax.swing.JFrame; 
import javax.swing.JPanel; 

public class CornerTest { 
    private JFrame frame; 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 
      public void run() { 
       try { 
        CornerTest window = new CornerTest(); 
        window.frame.setVisible(true); 
       } catch (Exception e) { 
        e.printStackTrace(); 
       } 
      } 
     }); 
    } 

    public CornerTest() { 
     initialize(); 
    } 

    private void initialize() { 
     frame = new JFrame(); 
     frame.setBounds(100, 100, 450, 450); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     final GeneralPath gp = new GeneralPath(); 
     MyGeneralPath path = new MyGeneralPath(gp); 
     path.moveTo(100, 100); 
     path.lineTo(200, 100); 
     path.lineTo(100, 50); 
//  path.lineTo(50, 100); 
     path.flush(); 


     JPanel panel = new JPanel() { 
      protected void paintComponent(Graphics g) { 
       Graphics2D g2d = (Graphics2D) g; 
       g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
         RenderingHints.VALUE_ANTIALIAS_ON); 
       g2d.setStroke(new BasicStroke(15.5f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); 
       g2d.setColor(Color.BLACK); 
       g2d.draw(gp); 
      } 
     }; 
     frame.setBackground(Color.CYAN); 
     frame.add(panel); 
    } 

    static class MyGeneralPath 
    { 
     private GeneralPath path; 
     private List<Point2D.Double> points = new ArrayList<Point2D.Double>(); 

     public MyGeneralPath(GeneralPath path) 
     { 
      this.path = path; 
     } 

     public void moveTo(double x, double y) 
     { 
      flush(); 
      points.add(new Point2D.Double(x, y)); 
     } 

     public void lineTo(double x, double y) 
     { 
      Point2D.Double point = new Point2D.Double(x, y); 

      checkSlope(point); 

      points.add(point); 
     } 

     private void checkSlope(Point2D.Double p3) 
     { 
      int size = points.size(); 

      if (size < 2) 
       return; 

      Point2D.Double p2 = points.get(size - 1); 
      Point2D.Double p1 = points.get(size - 2); 

      double slope1 = (p2.getY() - p1.getY())/(p2.getX() - p1.getX()); 
      double slope2 = (p3.getY() - p2.getY())/(p3.getX() - p2.getX()); 

      if (slope1 == slope2) 
       moveTo(p2.getX(), p2.getY()); 
     } 

     public void flush() 
     { 
      int size = points.size(); 

      if (size == 0) 
       return; 

      Point2D.Double point = points.get(0); 
      path.moveTo(point.getX(), point.getY()); 

      for (int i = 1; i < size; i++) 
      { 
       point = points.get(i); 
       path.lineTo(point.getX(), point.getY()); 
      } 

      points.clear(); 
     } 
    } 
} 
+0

感謝您的闡述。我的路徑經常變化,只是不斷用'paint'方法計算它是最簡單的。無論如何,事實證明,這並不像我想要運行這些計算那樣痛苦。雖然你的斜率比較比我所做的畢達哥拉斯計算更容易計算。 – The111 2013-03-23 05:21:45

2

不知道關於黑客攻擊的來源,但您可能可以自定義您的代碼,以便通過畫一條線來解決此問題:

path = new GeneralPath(); 
path.moveTo(100, 100); 
path.lineTo(200, 100); 
path.lineTo(50, 100); 

Rectangle bounds = path.getBounds(); 

if (bounds.height == 0) 
{ 
    path = new GeneralPath(); 
    path.moveTo(bounds.x, bounds.y); 
    path.lineTo(bounds.x + bounds.width, bounds.y); 
} 

if (bounds.width == 0) 
{ 
    path = new GeneralPath(); 
    path.moveTo(bounds.x, bounds.y); 
    path.lineTo(bounds.x, bounds.y + bounds.height); 
} 

g2d.draw(path); 
+0

是啊,我想類似的東西太多,但因爲我真正的應用程序我畫與500+一樣分的很長的路徑,這將增加不少的開銷,以我的繪畫方法來檢查每個「子路徑」,看看是否有回切。儘管它可能最終成爲最佳選擇。感謝您的意見。 – The111 2013-03-23 01:32:11