# Homogeneous coordinates in 2D, from scratch

Here’s an animation of a spinning, orbiting rectangle.
You can also see, in black, the *projection* of this rectangle,
as seen from the origin point (marked with a cross).
All of this is described with a tiny library
that uses *homogeneous coordinates*
to describe the rotation, scaling, translation, and projection.

In my previous post
I showed a matrix library in 5 lines of code.
Matrices can describe several operations you will use in graphics programming;
most importantly, *rotation* and *scaling*.

But for graphics programming,
plain linear algebra has at least two big deficiencies.
Linear functions can’t describe *translation* (that is, moving stuff!),
because they preserve the origin point.
And linear functions can’t describe *projection*
(that is, simulating a camera),
because they keep parallel lines parallel.

The *homogeneous coordinates* system is a kind of mathematical hack
that allows describing translation and projection.
It builds on top of plain linear algebra,
but adds an extra dimension, usually called *w*.
Imagine all true 2D points being drawn on the plane `w=1`

by a laser pen that sits at the origin.
Or again, the point `[2,3]`

is modelled by all points that pass through the straight line going through `[0,0,0]`

and `[2,3,1]`

(the laser line).
Or again more formally,
the two-dimensional point `[2,3]`

is modelled by all three-dimensional points `[2w, 3w, w]`

.

We can *translate* the two-dimensional drawing on the `w=1`

plane
by skewing space.
We move the `w`

basis vector by the amount to translate.

And we can *project* the two-dimensional drawing onto a one-dimensional line.
The very definition of homogeneous coordinates behaves like projection.
We can exploit this by squashing and skewing space.
(This projection transformation is a bit hard to describe.
I’ll try to animate it in a future post.)

Here is my 6-line homogeneous coordinates library (which builds on the 5-line matrix library in my previous post):

```
const rotateHom2d = a => [[Math.cos(a), Math.sin(a), 0], [-Math.sin(a), Math.cos(a), 0], [0, 0, 1]];
const scaleSepHom2d = (s) => [ [s[0], 0, 0], [0, s[1], 0], [0, 0, 1] ];
const scaleHom2d = s => scaleSepHom2d([s,s]);
const translateHom2d = v => [[1, 0, 0], [0, 1, 0], [v[0], v[1], 1]];
const unHom2d = ([x,y,w]) => [x/w, y/w];
// Projects from origin onto line y=1. Results are in x-coord after normalizing with `unHom2d`.
const projectHom2d = [ [1,0,0], [0,1,1], [0,0,0] ];
```

In this post, I described homogeneous coordinates for transforming 2D space, and projecting it onto a line. But it can be used in much the same way to transform 3D space, and project it onto a plane. I’ll show this in a future post.

This page copyright James Fisher 2020. Content is not associated with my employer.