What Loi Actually Looks Like in Practice
Most people encounter Loi (Line of Interest) when they're debugging routing, trading, or simulation systems and realize the numbers coming out don't match what the spec says they should. The theory is simple: you have a source, a destination, and a line connecting them. Everything in between is evaluated against that line. The implementation is where everything falls apart. I spent about three weeks last year tracking down why a LoI-based collision check was failing on diagonals. The issue wasn't the math — it was how floating point rounding accumulated differently depending on whether you calculated the line from point A to B versus B to A. The fix was symmetric normalization. You always compute the direction vector by subtracting the smaller coordinate index from the larger one, then normalize before doing any intersection tests. Standard stuff, once someone tells you.
Loi Example: The Basic Setup
Here is the minimal working case. You define two points, construct the vector, and test a third point against it. This gives you the perpendicular distance from any point to the infinite line. To clamp it to the segment itself, check whether t falls between zero and loi.length. If it doesn't, the closest point is one of the endpoints, and you return the distance to whichever one is nearer. The first edge case hits when your line is axis-aligned. If dx is zero, you are dividing by zero during normalization. If dy is zero, same problem. The workaround is a simple branch: if the length is below a threshold like 1e-10, skip the directional calculation entirely and treat the line as a point. Distance is just the distance to that point. This saves you from NaN values propagating through your entire system, which is worse than any incorrect distance.
The second edge case is more insidious. When you are checking hundreds or thousands of points against a Loi, you will be doing the same normalization over and over. Cache the direction vector and length. Recompute only when the start or end point changes. In my experience, this cut per-frame cost from roughly 0.4 milliseconds down to 0.06 milliseconds on a dataset of about 2,000 points. The numbers vary by hardware, but the ratio holds.
Get the Full Details

Loi Example: Segment Clamping in Action
Here is how you handle the clamped version where the line has finite length and you only care about the segment, not the infinite extension: The clamping is what separates a useful Loi from a theoretical one. Without it, you get false positives on points that are close to the line but far outside the actual segment. I saw a pathfinding bug caused by exactly this — units were being told to avoid obstacles that were nowhere near their route, just near the extended line. If you are working in a real-time system, avoid square roots where possible. The distance function above uses one at the end. If you only need to compare distances — say, finding the nearest point — skip the square root entirely and compare squared distances. You save a significant amount of CPU time, especially at scale.
For GPU work, the approach changes. You can encode the Loi as a single struct and run the projection math in parallel across thousands of threads. The bottleneck then becomes memory coalescing, not the arithmetic. Make sure your points are stored in Structure of Arrays format, not Array of Structures, or you will waste half your bandwidth.
Alternatives When Loi Is the Wrong Tool
Loi works well for pairwise checks. It does not scale to dynamic environments where lines move every frame and you need to re-evaluate hundreds of points against them. In those cases, a spatial partitioning structure like a quadtree or BVH is faster. You build the tree once per frame, insert your segments, and query points in logarithmic time instead of linear time. I switched one of my projects from brute-force Loi checks to a quadtree when the frame count dropped from 60 to about 22. The reconstruction cost of the tree was negligible compared to saving 1,800 distance calculations per frame. It is not always the right answer, but it is worth knowing when it is.
Loi Example: Common Pitfall with Rotating Lines
When the endpoints of your Loi rotate around a center point, the direction vector changes every frame. Do not re-normalize from scratch. Incremental rotation is cheaper: apply the rotation matrix to the previous frame's direction vector instead of recalculating from the new start and end coordinates. The error accumulates slightly over time, but you can re-normalize every sixty frames to correct drift. This kept a rotating radar sweep smooth at 120 FPS on hardware that stuttered badly with full recalculation. The core of Loi is projection math. Master the basic case, handle the degenerate ones, and pick the right data structure for your scale. That is what separates systems that work from systems that work until they don't.