2016-11-17 130 views
-1

我有問題搞清楚三件事情。 (使用繪圖面板創建的:http://www.buildingjavaprograms.com/DrawingPanel.javaJava:繪製明星和連接點與繪圖面板

問題1:繪製多邊形,使其居中且未彎曲。用更多的點畫出來並不明顯。

問題2:將星星的所有點連接在一起,所以它是一個巨大的圓圈(虛線)。我不明白爲什麼會發生這種情況,除非這種方法不是最好的。

問題3:當繪製的點數少時,我注意到它沒有正確繪製點,它看起來像一個正方形。

我真的很感謝幫助!

import java.awt.*; 

public class StarSampler { 

     public static void main(String[] args) 
     { 
      DrawingPanel panel = new DrawingPanel(500, 500); 
      Graphics2D g = panel.getGraphics(); 
      g.setColor(Color.BLUE); 

      fillStar(g, 250, 250, 150, 5, 1); 
     } 

     public static void fillStar(Graphics2D g, int ctrX, int ctrY, int radius, int nPoints, double spikiness) 
     { 
      double xDouble[] = new double[2*nPoints]; 
      double yDouble[] = new double[2*nPoints]; 
      int xPoint[] = new int[100]; 
      int yPoint[] = new int[100]; 

      for (int i = 0; i < 2*nPoints; i++) 
      { 
      double iRadius = (i % 2 == 0) ? radius : (radius * spikiness); 
      double angle = (i * 720.0)/(2*nPoints); 

      xDouble[i] = ctrX + iRadius * Math.cos(Math.toRadians(angle)); 
      yDouble[i] = ctrY + iRadius * Math.sin(Math.toRadians(angle)); 

      for (int j = 0; j < nPoints; j++) // Casts for ints and doubles 
      { 
       xPoint[j] = (int) xDouble[j]; 
       yPoint[j] = (int) yDouble[j]; 
      } 
      } 

      g.fillPolygon(xPoint, yPoint, nPoints); // Creates polygon 
      // Polygon gets drawn crookedly 
      g.drawPolyline(xPoint, yPoint, nPoints); // Draws lines to connect points 
      // Two lines go straight to (0,0) when nPonts*2 and nothing without *2? 
     } 
} 

我的輸出:

Wrong Output

我的目標輸出(如果沒有標記點,只是舉例兩顆星):

Correct Output

回答

2

與您的代碼的問題是邏輯性或由於馬虎編碼風格:

for (int j = 0; j < nPoints; j++) // Casts for ints and doubles 
     { 
      xPoint[j] = (int) xDouble[j]; 
      yPoint[j] = (int) yDouble[j]; 
     } 

這段代碼應該將多邊形的所有部分轉換爲整數。這段代碼有幾個問題:

  1. 它並沒有涵蓋所有要點。該循環產生總共2 * nPoints點,但只有一半被轉換。這是缺失峯值的來源
  2. 爲什麼在內循環中這樣做?這不應該在生成值的循環中完成。這只是大量的冗餘副本和劇集。
  3. 爲什麼要保留兩個單獨的數組?只需在創建時直接轉換它們。由於不會重複使用任何值,因此無論如何都要保持完全精確的值。

的圓爲360度,而不是720。這個代碼:

double angle = (i * 720.0)/(2*nPoints); 

會改變創建的點之間的角度。這意味着如果數字是偶數,或者產生大量交叉線(不會看起來不好,但不是你想要的,我想),你只能產生一半尖峯。

單位圓(與trignometry部分相關)的定義方式使得(1,0)是與中心成0°角的點。這也是您創建第一個高峯的地方。只需減去角度的90°即可將圓圈逆時針旋轉90°。

以下是基於您的代碼的工作解決方案。主方法只持有代碼來管理一個簡單的測試,UI:

import javax.swing.*; 
import java.awt.*; 
import java.awt.image.BufferedImage; 

public class StarSampler 
{ 
    private static final int WIDTH = 500, 
           HEIGHT = 500, 
           RADIUS = 200; 

    private static final double SPIKINESS = 0.5; 

    public static void main(String[] args) 
    { 
     BufferedImage bi = new BufferedImage(500, 500, BufferedImage.TYPE_4BYTE_ABGR); 
     updateImage(5, bi); 

     JFrame frame = new JFrame("Some Test"); 
     frame.setLayout(new BorderLayout()); 

     frame.add(new JLabel(new ImageIcon(bi)), BorderLayout.CENTER); 

     //menu to update number of spikes 
     JPanel sub = new JPanel(); 
     sub.setLayout(new BoxLayout(sub, BoxLayout.X_AXIS)); 
     sub.add(new JLabel("Spikes: ")); 
     JSpinner spikeSpinner = new JSpinner(new SpinnerNumberModel(5, 1, 500, 1)); 
     spikeSpinner.addChangeListener(e -> { 
      updateImage((Integer) spikeSpinner.getModel().getValue(), bi); 
      SwingUtilities.invokeLater(()->frame.repaint()); 
     }); 
     sub.add(spikeSpinner); 
     frame.add(sub, BorderLayout.SOUTH); 

     frame.pack(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 

    private static void updateImage(int nSpikes, BufferedImage bi) 
    { 
     int ctrX = WIDTH/2, ctrY = HEIGHT/2; 

     int nPoints = nSpikes * 2 + 1; 

     int xPoint[] = new int[nPoints]; 
     int yPoint[] = new int[nPoints]; 

     //generate star 
     for (int i = 0; i < nPoints; i++) 
     { 
      double iRadius = (i % 2 == 0) ? RADIUS : (RADIUS * SPIKINESS); 
      double angle = (i * 360.0)/(2*nSpikes); 

      xPoint[i] = (int) (ctrX + iRadius * Math.cos(Math.toRadians(angle - 90))); 
      yPoint[i] = (int) (ctrY + iRadius * Math.sin(Math.toRadians(angle - 90))); 
     } 

     //paint the star 
     Graphics2D g2 = (Graphics2D) bi.getGraphics(); 
     g2.setColor(Color.blue); 
     g2.fillRect(0, 0, WIDTH, HEIGHT); 
     g2.setStroke(new BasicStroke(4.f)); 
     g2.setColor(Color.yellow); 
     g2.drawPolyline(xPoint, yPoint, nPoints); 

     //insert control lines 
     g2.setStroke(new BasicStroke(1.f)); 
     g2.setColor(Color.black); 
     for(int i = 0; i < nSpikes * 2; i++) 
      g2.drawLine(ctrX, ctrY, xPoint[i], yPoint[i]); 

     int w1 = RADIUS, 
       w2 = (int) (RADIUS * SPIKINESS); 
     g2.drawOval(ctrX - w1, ctrY - w1, w1 * 2, w1 * 2); 
     g2.drawOval(ctrX - w2, ctrY - w2, w2 * 2, w2 * 2); 
    } 
} 
+0

這是我不好,我使用拉絲面板(http://www.buildingjavaprograms.com/DrawingPanel.java)不是的JPanel。但我真的很感激代碼,我正試圖理解你實現的邏輯。 – Aramza

+0

@Aramza UI組件並不重要。 'updateImage'方法包含所有繪製星標的邏輯,而'main'方法只處理UI並且它是創建的。 'updateImage'-Method的'BufferedImage'參數可以很容易地被'Graphics'對象替換。事實上,該參數只用一次;檢索所述'Graphics'-Object ... – Paul