hexagonal lattice rounding
How do you round coordinates on a hexagonal grid?
definitionhexagonal vs. visual space
definitionrendering transformationDefine the transformation by
This is the transformation that maps points in hexagonal-space coordinates to their visual positions. In particular, looks like this (dotted lines annotate hexagonal boundaries):
(insert diagram)
For any and , we will say that renders to to mean ; i.e., is the visual position of .
problemhexagonal roundingGiven , find so that the (Euclidean) distance between is minimized. That is to say, we wish to round to the nearest point on the hexagonal lattice.
Why is this not a trivial question? Why is the answer not just
(apply regular integer rounding to each coordinate)? The problem with this is that it minimizes distance only in regular orthogonal Cartesian spaceβweβd like to minimize distance in hexagonal space. This is best seen by plotting what it does visually:
DIAGRAM
In particular, in plain this collects points into square boxes, which after applying the render transformation turns into rhombi. So this clearly fails, because weβre looking for an algorithm that collects points into hexagonal boxes.
(For an explicit counterexample, take some small , consider the point , whose visual position is . Naively, this point rounds to ; however it is visually actually closer to or .)
OK, so how do we tackle this? Hereβs the approach I came up withβprobably not the most elegant, but I think itβs cute.
So, let be given. We will denote and also let denote the hexagonal-rounded coordinates we are trying to calculate. We will call the column and the row. Consider two cases based on :
-
If is less than distance away from its nearest integer, then we say is in a vertical section of the grid. In these sections the hexagonal boundaries are purely vertical (and column differentiation depends only on the visual position ). This is the simple case.
We know unambiguously that the row is . To calculate the column, observe that the lattice point at column renders to . So, relative to column zero, is horizontally offset by , whose nearest integer gives the column number .
-
If is more than distance away from its nearest integer, we say is in a zigzag section of the grid. In these sections weβre trying to differentiate between adjacent rows of hexagons, demarcated by the top/bottom boundaries of hexagons, which are slanted and zigzag-shaped.
To make these regions easier to analyze, letβs transform into yet another space, in which the zigzag hexagon boundaries become purely horizontal or vertical. Define by
Observe that under this mapping, the vectors parallel to the zigzag boundaries map to horizontal/vertical directions: , . Hereβs how the section looks under this mapping:
DIAGRAM
The neat thing to observe here is that, within the zigzag sections, the original hexagonal cutouts are now just unit half-squares. So we floor each coordinate, sending each square to its bottom-left corner, which we denote .
Back in visual space, each of these corners corresponds to the target hexagonβs left vertex along the zigzag. So let
At this point the vertical coordinate rounds to the row number , and the horizontal component shifted to the right by aligns with the center of the target hexagon, i.e., the column number .