Problem: Given a line segment on the cartesian plane, determine where and which order it intersects a regular grid. This sounds simple, but is actually quite a tough problem. It's related to, but distinct from, both Bresenham and supercover.
More specifically, consider:
- A line segment with start $(x_1, y_1)$ and end $(x_2, y_2)$
- A grid of cells, bounded by all lines $x = k$ and $y = k$ for all integer $k$
- Each cell therefore has four boundaries, called North, South, East, and West
The example plot shows the segment from (0.6,0.4) to (-0.2, 2.2) crossing three boundaries.
For a given line segment, we wish to determine the cell boundaries it crosses:
- For each boundary type, the number of crossing.
{N:2 S:0 E:0 W:1}in the example. - The sequence of crossings.
{N, W, N}in the example. - The grid position of each crossing, defined as $(x - floor(x), y - floor(y))$. Approximately
N: (0.35, 1), W: (0, 0.8), N: (0.8, 0)in the example.
I'll note that the problem as-is is not fully defined: line segments starting or ending on a boundary, coinciding with a boundary, and crossing a vertex all need definition. We can accept any reasonable, consistent definition of these.
Solving #1 is easy:
number of east (west if neg) crossings = floor(x2) - floor(x1)
number of north (south if neg) crossings = floor (y2) - floor(y2)
Solving #2 and #3 is surprisingly hard. I've come up with three approaches:
- Direct. The ideal would be to calculate this directly (that is, without iteration), similar to the formula for #1. I have made no progress here.
- Iterative. Determine the next crossing (by trying both directions and determining which is crossed first). Determine how far along the segment that is. Repeat until done. This works, though it lacks elegance or speed. The other issue is that chopping the segment repeatedly, if not done carefully, can cause inconsistency with floating point calculations leading to missed or double crossings.
- Mixed. Use the calculation above to determine the total number of crossings of each type. For each, one $(x,y)$ coordinate is an obvious integer, and the other can be solved using simple algebra, as can the length of the segment to that point. Sort by segment length.
#3 is the best approach so far. Is it possible to do better?
