如何在 jPanel 中调整多边形的大小?

How to re-size polygon in jPanel?

我必须制作一个程序,在随机大小的随机位置生成星星。我的代码已经在随机位置绘制了星星,但我无法随机更改它们的大小。我尝试为每个点分配一个大小因子以改变它们之间的距离,但星星都搞砸了。有我可以使用的缩放方法吗?

这是我目前所拥有的,它在随机位置绘制星星。

  final int MID = WIDTH / 2;
  final int TOP = 50;
    
  //sky
  Color skyColor = new Color(0, 0, 0);
  page.fillRect(0,0,getWidth(),getHeight());
    
  //ground
  Color groundColor = new Color(95,95,95);
  page.setColor(groundColor);
  page.fillRect(0,HEIGHT-20,getWidth(),getHeight());
  
  
  //star
  for (int i = 1; i <= starCount; i++)
  
  {
     int ranLocX = gen.nextInt(700 - 100) + 100;
     int ranLocY = gen.nextInt(300 - 75) + 75;
     int ranSize = gen.nextInt(8 - 1) + 1;
     
     int sizeXA = (-10 * ranSize);
     int sizeXB = (10 * ranSize);
     int sizeXC = (-5 * ranSize);
     int sizeXD = (-10 * ranSize);
     int sizeXE = (-10 * ranSize);
     int sizeXF = (-10 * ranSize);
     
     int sizeYC = (10 * ranSize);
     int sizeYD = (-10 * ranSize);
     int sizeYE = (10 * ranSize);
     
     page.drawPolygon(new int[] {xa + ranLocX, xb + ranLocX, xc + ranLocX, xd + ranLocX, xe + ranLocX, xf + ranLocX}, new int[] {ya + ranLocY, yb + ranLocY, yc + ranLocY, yd + ranLocY, ye + ranLocY, yf + ranLocY}, 6);
     
     
  }

下面是如何更改多边形大小的示例。我画了正方形,但任何形状都可以。

  • 只需创建一个 AffineTransform 的缩放实例并使用它来缩放形状。
  • 我使用 ThreadLocalRandom 随机选择要应用的比例。我总是复制原始多边形(template)然后缩放它。
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

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

public class Polygons extends JPanel {
      static int WIDTH = 500;
      static int HEIGHT = 500;
      JFrame f = new JFrame();
      Polygon b =new Polygon();
      ThreadLocalRandom r = ThreadLocalRandom.current();
      List<Shape> polys = new ArrayList<>();
      
      public static void main(String[] args) {
          SwingUtilities.invokeLater(()-> new Polygons().start());
      }
      public void start() {
          f.add(this);
          f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          f.pack();
          f.setLocationRelativeTo(null);
          f.setVisible(true);
          Polygon template = new Polygon();
          
              template.addPoint(0,0);
              template.addPoint(0,100);
              template.addPoint(100,100);
              template.addPoint(100,0);
          
//        AffineTransform rotate = AffineTransform.getRotateInstance(Math.toRadians(72.), )
           
          for (int i = 0; i < 20; i++) {
              Polygon p = new Polygon(template.xpoints,template.ypoints, template.npoints);
              p.translate(r.nextInt(WIDTH), r.nextInt(HEIGHT));
              double scale = r.nextInt(10,90)/100.;
              AffineTransform scaleIt = AffineTransform.getScaleInstance(scale,scale);
              
              polys.add(scaleIt.createTransformedShape(p));
              
          }
      }
      
      public Dimension getPreferredSize() {
          return new Dimension(WIDTH,HEIGHT);
      }
     
      @Override
      public void paintComponent(Graphics g) {
          super.paintComponent(g);
          Graphics2D g2d = (Graphics2D) g.create();
          g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                  RenderingHints.VALUE_ANTIALIAS_ON);
          for (Shape shape : polys) {
              g2d.draw(shape);
          }
      }
}

这是我很久以前写的东西,用于创建 5 点星。它画了一只手臂,然后旋转 72 度再画另一只,重复这个过程。

因为它是为了允许更改基数而编写的,因此可以更改星星的大小,这可能是缩放星星大小的更好选择,而不是使用上面提到的 AffineTransform

for (int i = 0; i < 50; i++) {

  // get the base of the next star between 5 and 29 inclusive                        
  int base = r.nextInt(5,30);
  Polygon star = createStar(base);

  // now randomly position it.                  
  star.translate(r.nextInt(0,400),r.nextInt(0,400));
  
  // and add to the list 
  polys.add(star);                                  
}

创建 5 分星

int startx = 250; // arbitrary starting points
int starty = 250;
public Polygon createStar(int armBase) {
    Polygon star = new Polygon();
    
    // The armBase is equal to one side of the inner
    // pentagon of the star
    
    // The height of the arm is the distance from the middle of the 
    // base to the tip of the stars arm. Since the tangent computes
    // ratio of the sides of a right triangle, multiplying by half
    // the base gives the other side, hence the height.
    int armHeight =
            (int) (armBase / 2 * Math.tan(Math.toRadians(72)));
    
    // The center offset is the distance from the middle of a given
    // base to the center of the inner pentagon.
    int centerOffset =
            (int) (armBase / 2 * Math.tan(Math.toRadians(54)));
    
    // this works by creating the first arm, rotating 72 degrees
    // and then adding the other two coodinates of succeeding arms.
    
    star.addPoint(startx, starty);
    star.addPoint(startx + armBase / 2, starty - armHeight);
    star.addPoint(startx + armBase, starty);
    for (int j = 0; j < 4; j++) {
        rotatePolygon(-Math.PI / 5 * 2, startx + armBase / 2,
                starty + centerOffset, star);
        star.addPoint(startx + armBase / 2, starty - armHeight);
        star.addPoint(startx + armBase, starty);
    }
    star.npoints--;
    
    star.translate(-star.getBounds().x,-star.getBounds().y); 
    return star;
}

// This is general purpose rotation that rotates about a center
// point. This can be derived using the double angle identities of
// for sin and cosine.
private void rotatePolygon(double ang, double sx, double sy,
        Polygon poly) {
    for (int j = 0; j < poly.npoints; j++) {
        double x = poly.xpoints[j];
        double y = poly.ypoints[j];
        double xx = sx + (x - sx) * Math.cos(ang)
                - (y - sy) * Math.sin(ang);
        double yy = sy + (x - sx) * Math.sin(ang)
                + (y - sy) * Math.cos(ang);
        poly.xpoints[j] = (int) xx;
        poly.ypoints[j] = (int) yy;
    }
}                                                    

这是一个绘制五角星的 GUI。

这是完整的可运行代码。我使用极坐标来计算绘制星星所需的 10 个点。我猜到了中间点正确的分数。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Polygon;

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

public class StarryNight2GUI implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new StarryNight2GUI());
    }

    @Override
    public void run() {
        JFrame frame = new JFrame("Starry Night");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        frame.add(new DrawingPanel(), BorderLayout.CENTER);
        
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }
    
    public class DrawingPanel extends JPanel {
        
        private static final long serialVersionUID = 1L;
        
        public DrawingPanel() {
            this.setBackground(Color.BLACK);
            this.setPreferredSize(new Dimension(640, 480));
        }
        
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            Color groundColor = new Color(95, 95, 95);
            g.setColor(groundColor);
            g.fillRect(0, getHeight() - 30, getWidth(), 30);
            
            Polygon polygon = createStar(new Point(320, 240), 80);
            g.setColor(Color.YELLOW);
            g.fillPolygon(polygon);
        }
        
        private Polygon createStar(Point centerPoint, int radius) {
            Polygon polygon = new Polygon();
            // 72, 144, 216, 288, 360
            // 36, 108, 180, 252, 324
            // 54, 126, 198, 270, 342
            // 18, 54, 90, 126, 162, 198, 234, 270, 306, 342
            for (int angle = 18; angle < 360; angle += 72) {
                double r = 0.42 * radius;
                Point point = toCartesian(centerPoint, angle, r);
                polygon.addPoint(point.x, point.y);
                point = toCartesian(centerPoint, angle + 36, radius);
                polygon.addPoint(point.x, point.y);
            }
            
            return polygon;
        }
        
        private Point toCartesian(Point centerPoint, int angle, double radius) {
            double theta = Math.toRadians(angle);
            int x = centerPoint.x + (int) Math.round(Math.cos(theta) * radius);
            int y = centerPoint.y + (int) Math.round(Math.sin(theta) * radius);
            return new Point(x, y);
        }
        
    }

}

这是一个简单的方法,您可以使用它来创建具有任意给定点数和半径的 Shape

 public static Shape radiusShape(int points, int... radii)
 {
    Polygon polygon = new Polygon();

    for (int i = 0; i < points; i++)
    {
        double radians = Math.toRadians(i * 360 / points);
        int radius = radii[i % radii.length];

        double x = Math.cos(radians) * radius;
        double y = Math.sin(radians) * radius;

        polygon.addPoint((int)x, (int)y);
    }

    Rectangle bounds = polygon.getBounds();
    polygon.translate(-bounds.x, -bounds.y);

    return polygon;
}

要创建 5 点星,您可以使用如下代码:

Shape star = ShapeUtils.radiusShape(10, 30, 12);

它将创建一个具有 5 个外部点和 5 个内部点的星形以赋予星形。

所以要随机化星星的大小,您需要随机化半径。

查看 Playing With Shapes 以了解您可以使用此方法创建的形状类型的更多示例。上面的radiusShape(...)方法取自上面link.

中找到的ShapeUtilsclass

然后我建议您创建一个具有属性 1) 形状 2) 点的自定义 class,这样您就可以在面板上的不同位置绘制星星。然后创建一个 ArrayList 来保存 class 的实例。在您的绘画方法中,您遍历此 ArrayList 以绘制每个 Shape。上面link也将提供这个概念的基本代码。