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

问题描述 投票:0回答:2

我在弄清楚三件事时遇到问题。 (使用绘图面板创建: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?
       }
}

我的输出:

我的目标输出(没有标记点,两颗星只是举例):

java loops drawing polygon
2个回答
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);

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

单位圆(与三角学部分相关)的定义方式使得 (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
投票

这是JavaFX的解决方案,我使用并修改了上面的代码。

import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.shape.Polygon;

public class poly_star extends Group {
    public poly_star(int RADIUS, int nSpikes, double SPIKINESS, Color col){
        int ind=0;
        int nPoints = nSpikes*2+1;
        // Define an array to store the points of the polygon
        double[] points = new double[nPoints * 2];
        // Loop through each point and calculate its position
        for (int i = 0; i < nPoints ; i++) {
            double iRadius = (i % 2 == 0) ? RADIUS : (RADIUS * SPIKINESS);
            // Calculate the angle for each point
            double angle = (i * 360.0) / (2*nSpikes);
    // X point position 
            points[ind] = iRadius * Math.cos(Math.toRadians(angle - 90));
    // Y point position
            points[ind+1] = iRadius* Math.sin(Math.toRadians(angle - 90));
            System.out.println("  i:"+i + " // ind:" + ind);
            ind +=2;
        }
        // Create a polygon object and set its points
        Polygon STARpoly = new Polygon(points);
        STARpoly.setFill(col);
        getChildren().add(STARpoly);
    }
}

您可以从任何地方调用它,只需添加您喜欢的参数即可:

 poly_star myStar = new poly_star(280,13,0.6,Color.YELLOW);
 myStar.setLayoutX( someXpos );
 myStar.setLayoutY( someYpos );
 getChildren().add(myStar);
© www.soinside.com 2019 - 2024. All rights reserved.