build-a-physics-engine / lesson-25.md
Lesson 25 · Collision detection

Polygon edge normals

The Separating Axis Theorem tests the directions a polygon's edges face, so first you need those outward normals. Today you compute them from counterclockwise vertices.

The goal

Compute the outward unit normal of every edge of a counterclockwise polygon.

Start here - the target
TO DO
Scenario: The outward normals of a square
Giventhe counterclockwise square {-1, -1}, {1, -1}, {1, 1}, {-1, 1}
Whenits edge normals are computed
Thenthey are {0, -1}, {1, 0}, {0, 1}, {-1, 0} in edge order (bottom, right, top, left)
Andeach normal is a unit vector pointing away from the polygon's interior
Background

The Separating Axis Theorem works by testing a handful of candidate directions, and for a polygon those directions are the outward normals of its edges. Each edge is the vector between two consecutive vertices; rotating that vector 90 degrees clockwise gives a perpendicular, and because the vertices are wound counterclockwise, that particular perpendicular always points outward, away from the interior. The formula is a tidy {edge.Y, -edge.X}, normalized to unit length.

That counterclockwise winding you insisted on two lessons ago is what makes the sign come out right without any per-polygon fiddling - reverse the winding and every normal would point inward. For the unit square the four normals are exactly the axis directions, which is the sanity check that the formula is correct. These normals are the axes you will project shapes onto next.

Make it work
// for a CCW polygon, the outward normal of edge (vi -> vi+1) is
// the edge vector rotated clockwise: {edge.Y, -edge.X}, normalized
func Normals(verts []Vec2) []Vec2 {
out := make([]Vec2, len(verts))
for i := range verts {
edge := Sub(verts[(i+1)%len(verts)], verts[i])
out[i] = Normalize(Vec2{edge.Y, -edge.X})
}
return out
}
CheckpointDONE
A polygon reports the outward normal of each edge. Commit and stop here.