JPanel implementation of an hexagonal map, with methods to convert between pixels and map coordinates (both directions, from map coordinates to pixels and viceversa)
import javax.swing.*;
import java.awt.*;
public class HexagonalMap extends JPanel {
private int width; // Number of columns
private int height; // Number of rows
private int hexSide; // Side of the hexagon
private int hexOffset; // Distance from left horizontal vertex to vertical axis
private int hexApotheme; // Apotheme of the hexagon = radius of inscribed circumference
private int hexRectWidth; // Width of the circumscribed rectangle
private int hexRectHeight; // Height of the circumscribed rectangle
private int hexGridWidth; // hexOffset + hexSide (b + s)
public HexagonalMap(int width, int height, int hexSide) {
this.width = width;
this.height = height;
this.hexSide = hexSide;
hexApotheme = (int) (hexSide * Math.cos(Math.PI / 6));
hexOffset = (int) (hexSide * Math.sin(Math.PI / 6));
hexGridWidth = hexOffset + hexSide;
hexRectWidth = 2 * hexOffset + hexSide;
hexRectHeight = 2 * hexApotheme;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
g.drawPolygon(buildHexagon(i, j));
}
}
}
@Override
public Dimension getPreferredSize() {
int panelWidth = width * hexGridWidth + hexOffset;
int panelHeight = height * hexRectHeight + hexApotheme + 1;
return new Dimension(panelWidth, panelHeight);
}
Polygon buildHexagon(int column, int row) {
Polygon hex = new Polygon();
Point origin = tileToPixel(column, row);
hex.addPoint(origin.x + hexOffset, origin.y);
hex.addPoint(origin.x + hexGridWidth, origin.y);
hex.addPoint(origin.x + hexRectWidth, origin.y + hexApotheme);
hex.addPoint(origin.x + hexGridWidth, origin.y + hexRectHeight);
hex.addPoint(origin.x + hexOffset, origin.y + hexRectHeight);
hex.addPoint(origin.x, origin.y + hexApotheme);
return hex;
}
Point tileToPixel(int column, int row) {
Point pixel = new Point();
pixel.x = hexGridWidth * column;
if (Util.isOdd(column)) pixel.y = hexRectHeight * row;
else pixel.y = hexRectHeight * row + hexApotheme;
return pixel;
}
Point pixelToTile(int x, int y) {
double hexRise = (double) hexApotheme / (double) hexOffset;
Point p = new Point(x / hexGridWidth, y / hexRectHeight);
Point r = new Point(x % hexGridWidth, y % hexRectHeight);
Direction direction;
if (Util.isOdd(p.x)) { //odd column
if (r.y < -hexRise * r.x + hexApotheme) {
direction = Direction.NW;
} else if (r.y > hexRise * r.x + hexApotheme) {
direction = Direction.SW;
} else {
direction = Direction.C;
}
} else { //even column
if (r.y > hexRise * r.x && r.y < -hexRise * r.x + hexRectHeight) {
direction = Direction.NW;
} else if (r.y < hexApotheme) {
direction = Direction.N;
} else direction = Direction.C;
}
return new Point(direction.getNeighborCoordinates(p));
}
public boolean tileIsWithinBoard(Point coordinates) {
int column = coordinates.x;
int row = coordinates.y;
return (column >= 0 && column < width) && (row >= 0 && row < height);
}
}