DSA Geometry
Computational Geometry
The drone must decide if obstacle C is left or right of segment AB before the next control tick. Floating atan2 is slow and brittle. Use an test from a .
Geometry algorithms are predicates plus careful . Hulls, intersections, and collision tests all bottom out here.
Algorithm journey
Orientation predicate
Sign of 2D cross product.
Handle collinear cases
On-segment tests, ties.
Compose algorithms
Hull, intersect, SAT, …
Choose robustness policy
Epsilon vs exact predicates.
What actually happens
Naive idea: compare angles or use floats with a universal 1e-9 epsilon. Breaks near the origin vs far away, and on nearly collinear points.
Better idea: decide turns with integer-friendly cross products when coordinates allow, and treat collinearity as a first-class case.
The improved design still fails without a robustness policy: topology bugs appear as missing edges, infinite loops in hulls, or false collision clears.
Invariant
Geometric algorithms must keep predicate outcomes consistent with the chosen arithmetic model. Mixing exact topology decisions with ad hoc float epsilons is how “impossible” diagrams appear.
How to choose geometry tools
1. Turn / side tests? Orientation via cross product.
2. Convex collision? Separating axis theorem.
3. Exact topology? Exact/adaptive predicates; do not hope.
Quantitative check
Graham scan / monotone chain hull is O(n log n) from sorting. Each orientation is O(1) arithmetic; the hidden cost is predicate failure rate under float noise, not the big-O line.
The foundation: orientation and cross products
In geometry, we don't use atan2 or angles (they are too slow and prone to precision errors). Instead, we use Orientation Tests based on Cross Products.
Interactive orientation predicate
Robust-predicate lab
Orientation decides the turn
cross(B−A, C−A)
26500
Sign: counter-clockwise.
For integer coordinates, compute products in a wide type. With floating inputs, epsilon is scale-dependent; robust predicates may need adaptive exact arithmetic.
Orientation and closed-segment intersection
General intersections require opposite-orientation tests; collinear cases additionally require inclusive bounding-box checks. These examples use exact integer arithmetic.
Python
from dataclasses import dataclass
@dataclass(frozen=True, order=True)
class Point:
x: int
y: int
def cross(a, b, c):
return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)
def on_segment(a, b, p):
return (cross(a, b, p) == 0 and
min(a.x, b.x) <= p.x <= max(a.x, b.x) and
min(a.y, b.y) <= p.y <= max(a.y, b.y))
def intersects(a, b, c, d):
o1, o2 = cross(a, b, c), cross(a, b, d)
o3, o4 = cross(c, d, a), cross(c, d, b)
if ((o1 > 0 > o2 or o2 > 0 > o1) and
(o3 > 0 > o4 or o4 > 0 > o3)):
return True
return ((o1 == 0 and on_segment(a, b, c)) or
(o2 == 0 and on_segment(a, b, d)) or
(o3 == 0 and on_segment(c, d, a)) or
(o4 == 0 and on_segment(c, d, b)))
assert intersects(Point(0, 0), Point(4, 4), Point(0, 4), Point(4, 0))Java
import java.math.BigInteger;
public final class SegmentIntersection {
record Point(int x, int y) {}
static BigInteger cross(Point a, Point b, Point c) {
long abx = (long) b.x() - a.x(), aby = (long) b.y() - a.y();
long acx = (long) c.x() - a.x(), acy = (long) c.y() - a.y();
return BigInteger.valueOf(abx).multiply(BigInteger.valueOf(acy))
.subtract(BigInteger.valueOf(aby).multiply(BigInteger.valueOf(acx)));
}
static boolean onSegment(Point a, Point b, Point p) {
return cross(a, b, p).signum() == 0
&& Math.min(a.x(), b.x()) <= p.x() && p.x() <= Math.max(a.x(), b.x())
&& Math.min(a.y(), b.y()) <= p.y() && p.y() <= Math.max(a.y(), b.y());
}
static boolean intersects(Point a, Point b, Point c, Point d) {
int o1 = cross(a, b, c).signum(), o2 = cross(a, b, d).signum();
int o3 = cross(c, d, a).signum(), o4 = cross(c, d, b).signum();
if (((o1 > 0 && o2 < 0) || (o1 < 0 && o2 > 0))
&& ((o3 > 0 && o4 < 0) || (o3 < 0 && o4 > 0))) return true;
return (o1 == 0 && onSegment(a, b, c)) || (o2 == 0 && onSegment(a, b, d))
|| (o3 == 0 && onSegment(c, d, a)) || (o4 == 0 && onSegment(c, d, b));
}
public static void main(String[] args) {
Point a = new Point(0, 0), b = new Point(4, 4);
Point c = new Point(0, 4), d = new Point(4, 0);
if (!intersects(a, b, c, d)) throw new AssertionError();
if (cross(a, b, new Point(2, 2)).signum() != 0) throw new AssertionError();
Point min = new Point(Integer.MIN_VALUE, Integer.MIN_VALUE);
Point max = new Point(Integer.MAX_VALUE, Integer.MAX_VALUE);
if (cross(min, max, new Point(Integer.MIN_VALUE, Integer.MAX_VALUE)).signum() <= 0) {
throw new AssertionError("full-range coordinates must not overflow");
}
}
}🛡️ Convex Hull: The Minimal Perimeter
Graham Scan (O(N log N))
The industry standard. It sorts points by angle and uses a stack to build the hull. It efficiently "pops" points that create a concave turn.
Monotone-chain hull invariant
Sort + deduplicate
Lexicographic (x,y) order gives deterministic endpoints; duplicates must not create zero edges.
Build lower/upper
While the last two hull points plus candidate make a forbidden turn, pop the middle point.
Collinear policy
Use ≤ 0 to discard boundary-interior collinear points, or < 0 to retain them; state the contract.
Sorting costs O(n log n); each point is pushed/popped at most once per chain, so the scan is O(n). Decide whether the result repeats the first point and what happens for 0, 1, 2, or all-collinear unique points.
Robustness is part of correctness
Integer coordinates
Differences and products can overflow before assignment. Cast operands before subtraction/multiplication; 32-bit coordinates may still exceed signed 64-bit cross products at full range, requiring bounded contracts or big integers.
Floating coordinates
A universal 1e-9 epsilon is not robust across scales. Use scale-aware tolerances for approximate product semantics, or adaptive/exact predicates when topology must be correct.
- • Test shared endpoints, touching, overlapping collinear segments, vertical/horizontal segments, zero-length segments, duplicates, and huge coordinates.
- • Separate broad-phase spatial indexing from exact narrow-phase predicates.
- • Avoid angle sorting with
atan2when orientation/quadrant comparators can remain exact. - • Property-test orientation antisymmetry and hull containment against a trusted library/oracle.
📦 Spatial Partitioning: Managing Scale
How do you find which of 1-million players is "closest" to an explosion without checking every player? (The Last-Mile problem in Game Engines).
K-D Trees
Higher Dimensional Search
Recursively splits space into half-spaces using axis-aligned hyperplanes. Excellent for Nearest Neighbor Search in ML and Robotics.
- Used in LiDAR processing.
- Efficient for range queries.
Quadtrees / Octrees
Recursive Grids
Splits a 2D space into 4 quadrants (8 for Octrees in 3D). If a quadrant has too many objects, it splits again.
- Used in Collision Detection (Unity/Unreal).
- Optimal for sparse distributions.
🎮 Application: Collision Detection
The Separating Axis Theorem (SAT)
A fundamental tool for detecting if two convex polygons are overlapping.Theorem: Two convex objects do NOT overlap if there exists an axis on which their projections do not overlap.
💡 Architectural Insight
In computational geometry, numerical robustness is part of the specification. For approximate measurements, choose an absolute/relative tolerance derived from coordinate scale and error budget, not a universal epsilon. When orientation or topology must be exact, use bounded integer arithmetic, wider/big integers, or adaptive exact predicates and handle degeneracies explicitly.
Short takeaway
Computational geometry starts from orientation predicates (2D cross products) and a robustness policy. Build hulls, intersections, and collision tests on consistent predicates.
Exercises
- Points A=(0,0), B=(10,0), C=(5,1e-12). What goes wrong with a fixed epsilon orientation test at different scales?
- Why prefer cross-product orientation over comparing atan2 angles for turn tests?
- State the Separating Axis Theorem in one sentence for convex polygons.
Primary sources
- de Berg et al., Computational Geometry: Algorithms and Applications.
- Preparata & Shamos: Computational Geometry.
- Shewchuk: Adaptive Precision Floating-Point Arithmetic and Fast Robust Geometric Predicates.