0

Im searching for an algorythem to get the location of a hexagon in a grid. I found this one but it doesnt seam to work:

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));
        }
    }

The output is kind of strange: output

This is the window-creating class(just a test class):

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);
    }
}

The Hexagon.java class:

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);
    }
}

As i said, this class worked just fine using non-rectangular shapes. There was no clipping or such.

6
  • It's not entirely clear what the question is, and where the Hexagon class comes from. However, I created some hexagon utility classes a while ago, and the computations are largely based on the excellent site redblobgames.com/grids/hexagons Commented Mar 6, 2018 at 8:58
  • I have a xand a y coordinate of the top, most left hexagon and im looking for an algorythem to find the x and y values for all the other hexagons on the grid. Commented Mar 6, 2018 at 9:13
  • Can you please post a compilable code snippet that sets up the window and all that stuff, with pink border etc.? The coordinates of the hexagons are easy, but setting up frames with all those exitOnClose-blah listeners for drawing polygons is annoying... Commented Mar 6, 2018 at 9:21
  • 1
    I have added the the code and the new output I get lately Commented Mar 6, 2018 at 9:33
  • Add the Hexagon class. (The fact that it seems to extend JComponent may already be a major issue here. Components are basically assumed to be rectangles, and trying to squeeze them into a hexagonal grid is likely to cause trouble...) Commented Mar 6, 2018 at 11:12

1 Answer 1

2

You've posted your definition of Hexagon too late, so I copy-pasted a modified version of a similar class from my collection of code snippets.


Here is one way to generate a hexagonal grid:

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();
        }
    }
}

It produces the following output:

enter image description here

Sorry for the lack of anti-aliasing. A few hints:

  • Height H of an equilateral triangle with unit side length is sqrt(3) / 2
  • The six offsets from the center are (0, +1), (H, +1/2), (H, -1/2), (0, -1), (-H, -1/2), (-H, +1/2), everything times side length.
  • Distance between rows is 1.5, distance between columns is 2 * H (times scaling constant = side length).
  • Every odd row is shifted by (0, H) (times scaling constant).
  • The position of (row,col)-th hexagon is (1.5 * row, 2 * H * (col + 0.5 * (row % 2))) (times constant).

If you want to rotate the hexagons such that two of their sides are horizontal, you have to flip rows and columns.

Sign up to request clarification or add additional context in comments.

3 Comments

The thing is, that you simply draw those on this JComponent. I would preffer to have every hexagon als an seperate object.
@EvenLonger The locations (and dimensions) of hexagons in your program are very likely to be correct, I've just compared your code with the code above: your code that determines location looks exactly the same, even the (j % 2)-part is exactly the same, strangely enough. Converting hexagons into JComponent has nothing to do with their location. It's a completely separate issue. As Marco13 has rightly pointed out, having hexagonal JComponents is nothing but trouble. I've just tried to compile and run your code: the best I could get was a single totally broken corner of one hexagon.
@EvenLonger Given that the entire awt/swing story was a nightmare back in the 2000's, now it is additionally obsolete & unsupported. I personally gave up at least half a decade ago any attempt to get anything out of this framework, except a single window with a maximized canvas (as in the above example). Is there any reason not to try it with JavaFX instead?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.