Projective geometric algebra

Reflections in PGA 2D

In PGA, a normalized line can act as a mirror. Point reflection is the base operation; polygon reflection applies the same action to each vertex.

The meet/join article used lines as constraints. A normalized line can also act as an operator. We stay in ganja's plane-based 2D PGA convention, Algebra(2,0,1): lines are grade-1 vectors, finite points are grade-2 bivectors, and a finite point still has the form 1e12 - x * 1e02 + y * 1e01.

Axis-aligned mirrors such as x = 0 or y = 0 reduce reflection to a coordinate sign change. An arbitrary normalized line handles the same operation directly.

Normalize The Mirror

A line is represented as

line = a e1 + b e2 + c e0

For reflection, the line should be normalized so the Euclidean normal has unit length:

length = sqrt(line.e1 * line.e1 + line.e2 * line.e2)
mirror = line / length

Representative scale leaves the geometry fixed. Normalization happens at the action boundary, so a different nonzero representative of the same line gives the same reflection.

Sandwich Action

Ganja writes the sandwich action with >>>:

P' = mirror >>> P

For a normalized mirror line, that action is the geometric reflection of the point. The explicit version is the same idea as mirror P reverse(mirror); ganja's operator matches the notation used in its PGA examples.

A polygon uses the same reflection formula on each vertex. Its vertices are finite PGA points, so each reflected vertex is another normalized point bivector.

One Reflection Reverses Orientation

The reflected polygon has the same edge lengths and the same distances to the mirror line, but its orientation flips. In ordinary graphics terms, one reflection changes handedness. The signed area before and after reflection records the reversal as a sign change.

Two reflections restore orientation and produce ordinary rigid motions: rotations when the mirror lines meet, translations when they are parallel.

From Points To Shapes

The same point action applies to every vertex of a shape:

P = e12 - x e02 + y e01
P' = mirror >>> P
  -> normalized finite point bivector

triangle.map((V) => mirror >>> V)
  -> normalized reflected point bivectors

The reflected shape is the collection of reflected vertex points. Keeping those points in bivector form keeps the operation in the algebra before converting back to coordinate tuples.