Geometric Primitives & Orientation
Computational geometry is built on a single reliable primitive — the orientation test, a sign of a cross product that tells whether three points turn left, right, or lie collinear. From points-as-vectors and the dot and cross products we derive orientation, segment intersection, the shoelace area formula, and point-in-polygon tests, keeping all arithmetic exact and integer so that no floating-point rounding can corrupt a sign.
╌╌╌╌
This lesson opens the computational geometry module, where the objects are points, segments, and polygons in the plane rather than numbers or graphs. The algorithms ahead, including convex hulls, sweep-line intersection, and closest pairs, look involved, but they nearly all rest on one tiny operation asked over and over: given three points, does the path through them turn left or right? Get that primitive exactly right and the rest is bookkeeping; get it subtly wrong and every structure built on top inherits the error.
The central design decision of this lesson is therefore exact arithmetic. The natural geometric quantities (angles, lengths, slopes) are irrational and force floating point, where a quantity that should be zero comes out as and a collinearity test flips the wrong way. We avoid them. With integer input coordinates, the orientation and area primitives below are polynomials in the coordinates, so they evaluate to exact integers and their signs are never in doubt.1 Slopes, square roots, and never appear.
Points as vectors
We identify a point with the vector from the origin to it, which lets us do arithmetic on geometry. For points and and a scalar :
The subtraction is the one that does the work: it is the displacement vector pointing from to , and almost every primitive below is phrased in terms of such difference vectors anchored at a common point. If , have integer coordinates, so does , and exactness is preserved by every one of these operations.
The dot product: angle and projection
The dot product of two vectors measures how much they point the same way:
where is the angle between them. The second equality is the useful one in reverse: because , the sign of the dot product is the sign of , so it classifies the angle without ever computing it.
Three uses recur. Projection: the scalar projection of onto is , the signed length of 's shadow along . Perpendicularity: , an exact integer test. Angle: when the actual angle is genuinely needed (the one place a square root sneaks in). Note the dot product is symmetric and tells us nothing about which side one vector lies on; for that we need its companion.
The cross product: signed area and orientation
In the plane the cross product of two vectors is a single scalar:
Its magnitude equals the area of the parallelogram spanned by and (and twice the area of the triangle they form). Its sign is the sign of , which encodes orientation: positive when lies counterclockwise from , negative when clockwise, zero when the two are parallel (collinear). Unlike the dot product, the cross product is antisymmetric: . This single quantity, an exact integer for integer inputs, is the seed of nearly everything that follows.
The orientation test
Anchor two difference vectors at a common point and take their cross product.
This is the orientation (or ccw
) test, the fundamental primitive of
planar computational geometry:
It reports the sense of the turn made by the directed path :
Three properties make this primitive so powerful. It uses only additions and
multiplications of the input coordinates, so for integer inputs it is exact. It
is antisymmetric in a way that respects the geometry: swapping and
flips the sign, matching the reversal of the turn. And it answers, in , the
question every higher geometric algorithm reduces to — which side of the line
does lie on? The collinearity test are , , on one line?
is
just , with no division by a slope and hence no
vertical-line special case.
- 1
- 2if then
- 3returnleft turn
- 4else if then
- 5returnright turn
- 6else
- 7returncollinear
Segment intersection
When do two segments and cross? The slope-and-solve approach drags in division and degenerate cases; orientation makes it a handful of sign comparisons. The key idea is straddling: segment straddles the line through and when its endpoints fall on opposite sides of that line, that is, when and have opposite signs.
Why. If and are strictly on opposite sides of line , the open
segment crosses that line exactly once, at some point ; the
symmetric condition forces to also lie strictly between and . Both
products being negative pins the crossing to the interior of both segments. The
two ccw evaluations are exact integers, so this test has no rounding error
and never computes the intersection point itself.
The boundary, when some ccw is and three points are collinear, needs
care, and is where naive implementations break. The case logic:
- All four products nonzero (the generic case): intersect iff both products are strictly negative, as above.
- Exactly one is , say :
then lies on the line ; the segments touch iff lies on the segment, i.e. 's coordinates are within the bounding box of and
(an
on-segmentcheck: and likewise for ). - The segments are collinear (all four
ccwvanish): they overlap iff their -D projections onto the -axis (or , if vertical) overlap, again a bounding-box / interval-overlap test, no geometry beyond comparisons.
- 1
- 2
- 3if and then
- 4return trueproper crossing
- 5if and then return true
- 6if and then return true
- 7if and then return true
- 8if and then return true
- 9return false
Polygon area: the shoelace formula
Given a polygon as an ordered list of vertices (indices modulo ), its area is the shoelace formula:
Each term is exactly the cross product , so the area is a sum of cross products, halved.
Drop the absolute value and the sign of the sum carries orientation: positive means the vertices are listed counterclockwise, negative means clockwise. This is the cheapest way to detect the winding direction of a polygon, and because the sum is an integer for integer vertices, the area comes out as an exact half-integer.2
Point in polygon
Is a query point inside a polygon? Two exact strategies, both built from the
primitives above. Ray casting shoots a ray from in a fixed direction (say
) and counts how many polygon edges it crosses: an odd count means is
inside, even means outside — the Jordan-curve parity argument. Each
ray-vs-edge crossing is decided with the same straddle/orientation tests, with
careful tie-breaking when the ray grazes a vertex (count an edge only if exactly
one endpoint is strictly above the ray). The winding number alternative sums
the signed angles the polygon's edges subtend at (computed from cross- and
dot-product signs, not actual angles); a total winding of means outside,
means inside, and unlike parity it stays correct for self-intersecting
polygons. For a convex polygon both can be sped up to : binary-search
the vertex fan around to find the wedge containing using orientation
tests, then one final ccw against the bounding edge decides inside vs. outside.3
For a convex polygon the fan of diagonals from cuts the interior into triangular wedges in angular order, so a single binary search on locates the wedge that could contain ; one last orientation test against the edge decides inside vs. outside.
Takeaways
- Treat points as vectors; the difference is the displacement that almost every primitive is built from, and integer inputs stay integer.
- The dot product has the sign of : positive/zero/negative acute/right/obtuse — it handles projection, perpendicularity, and angle.
- The cross product gives signed parallelogram area in its magnitude and orientation in its sign.
- The orientation test reports left/right/collinear in exact integer arithmetic — the primitive that hull, intersection, and point-location all reduce to.
- Segments cross iff each straddles the other's line (opposite
ccwsigns on both); collinear and touching cases fall to on-segment bounding-box checks. - The shoelace formula is a sum of cross products giving area, and its sign reveals CCW vs. CW winding.
- Point-in-polygon is ray-casting parity or winding number; a convex polygon admits an orientation-based binary search.
Footnotes
- CLRS, Ch. 33 — Computational Geometry (§33.1): cross-product primitives, the orientation/turn test, and segment-intersection via straddling, all in exact arithmetic to avoid round-off. ↩
- Skiena, § — Computational Geometry: the shoelace (surveyor's) formula for polygon area as a sum of cross products, whose sign gives vertex orientation. ↩
- Erickson, Ch. — (geometry): point-in-polygon by ray-crossing parity and winding number, and the convex case via orientation-guided binary search. ↩
╌╌ END ╌╌