【问题标题】:Java - Hexagon location in gridJava - 网格中的六边形位置
【发布时间】:2018-03-06 08:48:36
【问题描述】:

我正在寻找一种算法来获取网格中六边形的位置。 我找到了这个,但它无法正常工作:

for(int i = 0; i < width; i++) {
        for(int j = 0; j < height; j++) {
            grid[i][j] = new Hexagon(x+(j*((3*Hexagon.S)/2)), y+((j%2)*Hexagon.A)+(2*i*Hexagon.A));
        }
    }

输出有点奇怪: output

这是创建窗口的类(只是一个测试类):

import java.awt.Container;

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

public class Grid extends JPanel {

    private static final long serialVersionUID = 1L;

    public static void main(String[] args) {
        int width = 2;
        int height = 4;
        int x = 100;
        int y = 100;
        Hexagon[][] grid = new Hexagon[width][height];

        JFrame f = new JFrame();
        Container cp = f.getContentPane();


        for(int i = 0; i < width; i++) {
            for(int j = 0; j < height; j++) {
                grid[i][j] = new Hexagon(x+(j*((3*Hexagon.S)/2)), y+((j%2)*Hexagon.A)+(2*i*Hexagon.A));
                cp.add(grid[i][j]);
            }
        }

        f.setLayout(null);
        f.setBounds(100, 100, 300, 300);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
    }
}

Hexagon.java 类:

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;

import javax.swing.JButton;

 public class Hexagon extends JButton {

    public static final int S = 50;
    public static final int A = (int) (Math.sqrt(3)*(S/2));

    private static final long serialVersionUID = 1L;
    private final int x, y;
    private final Polygon shape;

    public Hexagon(int x, int y) {
        this.x = x;
        this.y = y;
        this.shape = initHexagon();
        setSize(2*S, 2*A);
        setLocation(x-S, y-A);
        setContentAreaFilled(false);
    }

    private Polygon initHexagon() {
        Polygon p = new Polygon();
        p.addPoint(x+(S/2), y-A);
        p.addPoint(x+S, y);
        p.addPoint(x+(S/2), y+A);
        p.addPoint(x-(S/2), y+A);
        p.addPoint(x-S, y);
        p.addPoint(x-(S/2), y-A);
        return p;
    }

    protected void paintComponent(Graphics g) {
        g.setColor(Color.BLACK);
        g.drawPolygon(this.shape);
    } 

    protected void paintBorder(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        g2.setColor(Color.BLACK);
        g2.setStroke(new BasicStroke(4));
        g2.drawPolygon(this.shape);
    }

    public boolean contains(int x, int y) {
        return this.shape.contains(x, y);
    }
}

正如我所说,这个类使用非矩形形状工作得很好。 没有剪裁之类的。

【问题讨论】:

  • 目前还不完全清楚问题是什么,以及Hexagon 类的来源。不过,我前段时间创建了一些hexagon utility classes,计算主要基于优秀网站redblobgames.com/grids/hexagons
  • 我有一个x和一个y顶部坐标,最左边的六边形,我正在寻找一个算法来找到所有其他六边形的xy值网格。
  • 您能否发布一个可编译的代码 sn-p 设置窗口和所有这些东西,带有粉红色边框等?六边形的坐标很简单,但是用所有那些用于绘制多边形的 exitOnClose-blah 侦听器设置框架很烦人......
  • 我已经添加了代码和我最近得到的新输出
  • 添加Hexagon 类。 (它似乎扩展JComponent 的事实可能已经是这里的一个主要问题。组件基本上假设为矩形,并且试图将它们挤压成六边形网格可能会造成麻烦。。 .)

标签: java jcomponent hexagonal-tiles


【解决方案1】:

您发布 Hexagon 的定义太晚了,所以我从我的代码 sn-ps 集合中复制粘贴了一个类似类的修改版本。


这是生成六边形网格的一种方法:

import java.awt.Container;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JComponent;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.GridLayout;
import java.util.function.*;

public class Hexagons extends JPanel {

    private static final long serialVersionUID = 1L;

    /** Height of an equilateral triangle with side length = 1 */
    private static final double H = Math.sqrt(3) / 2;

    static class Hexagon {
      final int row;
      final int col;
      final double sideLength;
      public Hexagon(int r, int c, double a) {
        this.row = r;
        this.col = c;
        this.sideLength = a;
      }

      double getCenterX() {
        return 2 * H * sideLength * (col + (row % 2) * 0.5);
      }

      double getCenterY() {
        return 3 * sideLength / 2  * row;
      }

      void foreachVertex(BiConsumer<Double, Double> f) {
        double cx = getCenterX();
        double cy = getCenterY();
        f.accept(cx + 0, cy + sideLength);
        f.accept(cx - H * sideLength, cy + 0.5 * sideLength);
        f.accept(cx - H * sideLength, cy - 0.5 * sideLength);
        f.accept(cx + 0, cy - sideLength);
        f.accept(cx + H * sideLength, cy - 0.5 * sideLength);
        f.accept(cx + H * sideLength, cy + 0.5 * sideLength);
      }
    }

    public static void main(String[] args) {
        final int width = 50;
        final int height = 50;
        final Hexagon[][] grid = new Hexagon[height][width];
        for(int row = 0; row < height; row++) {
            for(int col = 0; col < width; col++) {
                grid[row][col] = new Hexagon(row, col, 50);
            }
        }

        JFrame f = new JFrame("Hexagons");
        f.getContentPane().setLayout(new GridLayout());
        f.getContentPane().add(new JComponent() {
          @Override public void paint(Graphics g) {
            g.setColor(new Color(0xFF, 0xFF, 0xFF));
            g.fillRect(0,0,1000,1000);
            g.setColor(new Color(0,0,0));
            final int[] xs = new int[6];
            final int[] ys = new int[6];
            for (Hexagon[] row : grid) {
              for (Hexagon h: row) {
                final int[] i = {0};
                h.foreachVertex((x, y) -> {
                  xs[i[0]] = (int)((double)x);
                  ys[i[0]] = (int)((double)y);
                  i[0]++;
                });
                g.drawPolygon(xs, ys, 6);

                g.drawString(
                  "(" + h.row + "," + h.col + ")", 
                  (int)(h.getCenterX() - 15), 
                  (int)(h.getCenterY() + 12)
                );
              }
            }
          }
        });
        f.setBounds(0, 0, 500, 500);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
        try {
            Thread.sleep(100);
        } catch (Throwable e) {

        } finally {
            f.repaint();
        }
    }
}

它产生以下输出:

很抱歉缺少抗锯齿功能。一些提示:

  • 单位边长的等边三角形的高度Hsqrt(3) / 2
  • 距中心的六个偏移量是(0, +1)(H, +1/2)(H, -1/2)(0, -1)(-H, -1/2)(-H, +1/2),一切都乘以边长。
  • 行间距为1.5,列间距为2 * H(乘以缩放常数=边长)。
  • 每个奇数行移动(0, H)(倍数缩放常数)。
  • (row,col)-th 六边形的位置是(1.5 * row, 2 * H * (col + 0.5 * (row % 2)))(时间常数)。

如果要旋转六边形,使其两侧水平,则必须翻转行和列。

【讨论】:

  • 问题是,您只需在 JComponent 上绘制它们即可。我更愿意让每个六边形都成为一个单独的对象。
  • @EvenLonger 您的程序中六边形的位置(和尺寸)非常可能是正确的,我刚刚将您的代码与上面的代码进行了比较:您的代码确定位置看起来完全一样,即使(j % 2)-part 完全一样,很奇怪。将六边形转换为JComponent 与它们的位置无关。这是一个完全独立的问题。正如 Marco13 正确指出的那样,拥有六边形 JComponents 只不过是麻烦。我刚刚尝试编译并运行您的代码:我能得到的最好结果是一个六边形的一个完全破碎的角。
  • @EvenLonger 鉴于整个 awt/swing 故事在 2000 年代是一场噩梦,现在它也已过时且不受支持。至少五年前,我个人放弃了从这个框架中获取任何东西的任何尝试,除了带有最大化画布的单个窗口(如上例所示)。有什么理由不改用JavaFX 试试吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-27
  • 2018-05-27
  • 1970-01-01
相关资源
最近更新 更多