Java:使用绘图面板绘制星形和连接点

时间:2016-11-17 19:08:22

标签: java loops drawing polygon

我遇到了解决三件事的问题。 (使用绘图面板创建:http://www.buildingjavaprograms.com/DrawingPanel.java

问题#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

1 个答案:

答案 0 :(得分: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. 为什么在内循环?这不应该在生成值的循环中完成。这只是大量的冗余副本和演员表。
  4. 为什么要保留两个独立的阵列?只需在创建时直接转换它们。由于没有重复使用任何值,因此无论如何都要保持一个完全精确的值。
  5. 圆圈是360度,而不是720度。此代码:

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

    将改变创建点之间的角度。这意味着你要么只生成一半的尖峰,如果数量是偶数,要么产生大量的交叉线(看起来也不错,但不是你想要的,我猜)。

    单位圆(与三角测量部分相关)以这样的方式定义:(1,0)是与中心成0°角的点。这也是您创建第一个尖峰的地方。简单地减去90°的角度,使圆圈逆时针旋转90°。

    这是基于您的代码的工作解决方案。 main方法只保存代码来管理简单的测试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);
        }
    }