NAME
Math::Geometry::HexGrid - Fast, XS-accelerated hexagonal grid mathematics
SYNOPSIS
use Math::Geometry::HexGrid qw(:all);
# 1. High-Performance Functional Interface (Pure C Speed)
# Convert odd-r offset coordinates to 3D cube coordinates:
my ($q, $r, $s) = oddr_to_cube(15, 12); # (9, 12, -21)
my ($col, $row) = cube_to_oddr($q, $r, $s);
# Calculate exact Manhattan hex distance:
my $dist = hex_distance(0, 0, 15, 12);
# Check if two coordinates lie along a common cardinal hex axis:
if (hex_is_collinear($c1, $r1, $c2, $r2)) {
my @ray = hex_collinear_ray($c1, $r1, $c2, $r2);
for my $step (@ray) {
say "Step: $step->[0], $step->[1]";
}
}
# Fetch 6 immediate neighbors (respects odd-r row parity):
my @neighbors = hex_neighbors(4, 4);
# 2. Object-Oriented Interface (Ergonomic Value Objects)
my $h1 = Math::Geometry::HexGrid->hex(4, 4);
my $h2 = Math::Geometry::HexGrid->hex(10, 4);
say $h1->col; # 4
say $h1->row; # 4
say $h1->distance_to($h2); # 6
say "$h1"; # Overloaded stringification: "4,4"
if ($h1 == $h2) {
# Overloaded equality in C
}
my @nbs = $h1->neighbors; # Returns Math::Geometry::HexGrid::Hex objects
DESCRIPTION
Math::Geometry::HexGrid provides high-performance, exact hexagonal grid mathematics implemented in ANSI C with Perl XS bindings.
Working with hexagonal grids in standard Cartesian ($col, $row) offset coordinates is notoriously error-prone because movement vectors change depending on row or column parity. By mapping offset coordinates to symmetric 3-axis Cube Coordinates ($q, $r, s) where $q + $r + $s == 0, all hexagonal operations (distance, direction, adjacency, and line-drawing) become simple, branch-free linear algebra.
All mathematical operations use pure integer arithmetic, completely avoiding floating-point roundoff errors and precision drift.
MATHEMATICAL FOUNDATIONS & ALGORITHMS
This module implements pointy-topped hexagonal grids with odd-r offset layout (where odd-numbered rows are shifted to the right by half a hex width).
1. Coordinate Systems
Odd-R Offset Coordinates
($col, $row):Standard 2D array coordinates convenient for map storage and display.
Cube Coordinates
($q, $r, $s):A 3D coordinate system where each axis corresponds to one of the three primary hexagonal diagonal directions, constrained to the diagonal plane:
q + r + s = 0
2. Conversion Formulas
Conversion between odd-r offset and cube coordinates is an exact, reversible integer bijection:
Offset to Cube
q = col - floor((row - (row & 1)) / 2)
r = row
s = -q - r
Because row - (row & 1) is always an even integer, dividing by 2 yields an exact integer without fractional truncation.
Cube to Offset
col = q + floor((r - (r & 1)) / 2)
row = r
3. Hexagonal Distance
The shortest path distance between two hexes in a regular grid is defined by the Manhattan metric in cube coordinates:
distance = max(|q1 - q2|, |r1 - r2|, |s1 - s2|)
Equivalently:
distance = (|q1 - q2| + |r1 - r2| + |s1 - s2|) / 2
4. Adjacency & Direction Offsets
Every hexagon has exactly 6 neighbors. In cube coordinates, neighbor directions are unit permutations of (+1, -1, 0):
Direction 0 (East): (+1, 0, -1)
Direction 1 (Northeast): (+1, -1, 0) [or (+1, -1) in odd rows]
Direction 2 (Northwest): ( 0, -1, +1)
Direction 3 (West): (-1, 0, +1)
Direction 4 (Southwest): (-1, +1, 0)
Direction 5 (Southeast): ( 0, +1, -1)
hex_neighbors maps these offsets directly to odd-r coordinates taking row parity into account.
5. Collinear Line-Drawing & Raycasting
Two hexes are collinear if and only if they lie along a common straight line parallel to one of the 3 cube axes:
q1 == q2 OR r1 == r2 OR s1 == s2
hex_collinear_ray traces intermediate hexes by interpolating along the shared axis, rounding each step to integer coordinates.
FUNCTIONAL API
The following subroutines are available for export. Use the tag :all to import all of them:
use Math::Geometry::HexGrid qw(:all);
oddr_to_cube($col, $row)
my ($q, $r, $s) = oddr_to_cube($col, $row);
Converts 2D odd-r offset coordinates ($col, $row) to 3D cube coordinates ($q, $r, $s). Returns a 3-element list of integers.
cube_to_oddr($q, $r, $s)
my ($col, $row) = cube_to_oddr($q, $r, $s);
Converts 3D cube coordinates ($q, $r, $s) back to 2D odd-r offset coordinates. Returns a 2-element list of integers ($col, $row).
hex_distance($col1, $row1, $col2, $row2)
my $dist = hex_distance($col1, $row1, $col2, $row2);
Calculates the exact integer Manhattan hex distance between two hexes.
hex_is_collinear($col1, $row1, $col2, $row2)
if (hex_is_collinear($c1, $r1, $c2, $r2)) { ... }
Returns a boolean indicating whether the two hex coordinates share one of the 6 cardinal hexagonal axes. Returns false if the coordinates are identical.
hex_neighbors($col, $row)
my @nbs = hex_neighbors($col, $row);
Returns a 6-element list of array references ([$c, $r], ...) representing the immediate neighboring coordinates in clockwise order starting from East (direction 0).
hex_collinear_ray($col1, $row1, $col2, $row2, [$max_length = 100])
my @ray = hex_collinear_ray($col1, $row1, $col2, $row2, $max_len);
Traces a straight line from ($col1, $row1) toward ($col2, $row2). Returns an empty list if the two points are not collinear. Otherwise, returns a list of array references ([$c, $r], ...) beginning with the first step past the origin, up to $max_length steps or reaching the destination.
OBJECT-ORIENTED API
For higher-level application logic, Math::Geometry::HexGrid provides a lightweight value object class Math::Geometry::HexGrid::Hex.
All OO methods are implemented in native C/XS with zero Perl method-call overhead.
Math::Geometry::HexGrid->hex($col, $row)
Math::Geometry::HexGrid::Hex->new($col, $row)
my $hex = Math::Geometry::HexGrid->hex($col, $row);
Constructs and returns a new hex coordinate value object.
$hex->col
Returns the integer column coordinate.
$hex->row
Returns the integer row coordinate.
$hex->to_cube
my ($q, $r, $s) = $hex->to_cube;
Returns the 3D cube coordinates ($q, $r, $s) as a list.
$hex->distance_to($other)
my $d = $hex->distance_to($other_hex);
Returns the integer hex distance to another Math::Geometry::HexGrid::Hex object.
$hex->is_collinear_with($other)
if ($hex->is_collinear_with($other)) { ... }
Returns true if both hex objects are collinear.
$hex->neighbors
my @neighbors = $hex->neighbors;
Returns a list of 6 new Math::Geometry::HexGrid::Hex objects representing the adjacent neighbors.
$hex->ray_to($other, [$max_length = 100])
my @ray = $hex->ray_to($other, 5);
Returns a list of Math::Geometry::HexGrid::Hex objects representing the collinear ray toward $other.
$hex->equals($other)
Returns true if both coordinates have identical column and row values.
Overloaded Operators
The Math::Geometry::HexGrid::Hex class overloads the following operators:
Stringification (
""): Formats as"col,row"(e.g."4,7"), making hex objects natural hash keys.Equality (
==): Checks exact integer equality in native C.Inequality (
!=): Inverted equality check.
SEE ALSO
Red Blob Games Hexagonal Grids Guide: https://www.redblobgames.com/grids/hexagons/
The canonical reference for hexagonal grid mathematics and algorithms.
AUTHOR
Steffen Mueller <cpan@steffen-mueller.net>
COPYRIGHT AND LICENSE
Copyright (C) 2026 Steffen Mueller
This software is released under the MIT License. See the LICENSE file included with this distribution for full license details.