Easily Dealing With Any-Dimensional Planes
published on Dec 24 2025
Writing the post from yesterday reminded me of another well-known representation for a geometric primitive, the plane, that makes code pleasing to look at and simple.
Planes
In general, a "plane" is an n-1 dimensional sub-space of an n-dimensional space that is flat. There's a mathematically rigorous definition of what "flat" really means, but intuitive understanding is sufficient for the purposes of this explanation.
To fully specify a plane, we only need two things: the plane's normal vector (which we'll call `n`) and any point within the plane (we'll refer to it as `o`). But we don't actually need to store both the point and the vector in our representation.
By definition, the plane's normal vector should be orthogonal to any vector within the plane (their dot product has to be 0). Therefore, if a point `p` belongs to the plane, the following must be true:
dot(p - o, n) = 0
Let's for now assume the 3D case and expand the above expression to individual coordinates (everything works exactly the same for N-dimensional case). We'll get:
(p_x - o_x) * n_x + (p_y - o_y) * n_y + (p_z - o_z) * n_z = 0
// which can be rewritten as
p_x * n_x + p_y * n_y + p_z * n_z - (o_x * n_x + o_y * n_y + o_z * n_z) = 0
// or otherwise:
dot(p, n) - dot(o, n) = 0
Turns out that in order to determine whether a point lies on a plane, we actually need just the normal vector and the scalar value `dot(o, n)`. If we recall that the dot product is the length of the projection of one vector onto the other, it's easy to see that `dot(o, n)` is simply the distance from the coordinate space origin to the plane along the direction of the normal vector.
This suggests the following representation:
template <class ScalarT=float, unsigned N = 3>
using hyperplane = vec<ScalarT, N+1>
Assuming that your plane's normal vector is already of unit length, it's really easy to make a new plane (if the normal isn't unit length, you'd have to normalize it first):
template<class ScalarT, unsigned N>
hyperplane<ScalarT, N> make_hyperplane_fast(vec<ScalarT, N> normal, vec<ScalarT, N> origin) {
return hyperplane<ScalarT, N> {normal, -dot(normal, origin)};
}
Operations With Planes
We used `-dot(normal, origin)` above because this helps us to find the distance from any given point to the plane using a single dot product between N+1 dimensional vectors (assuming the N+1-th coordinate of the point is 1.0):
template<class ScalarT, unsigned N>
ScalarT point_to_hyperplane_dist(const hyperplane<ScalarT, N>& pl, vec<ScalarT, N> pt) noexcept {
return dot(pl, vec<ScalarT, N + 1> {pt, (ScalarT)1});
}
Checking if two planes are parallel is also trivially easy: we only need to compute the cross product between the normal vectors - it should be zero if and only if the planes are parallel. If the planes are parallel, the distance between them can be found by subtracting the distances of the planes from the coordinate space origin.
If we multiply the normal vector by `dot(o, n)`, we will get the coordinates of a point that lies on the plane. Using this "origin point", we can easily transform the plane from one coordinate system to another: simply apply your transform to both the origin point and the normal, and construct a new plane from the results. Of course, the usual caveats about transforming normal vectors apply.
Generalization
This logic generalizes to higher dimensions (4,5,...-dimensional hyperplanes), but it also generalizes "down" to the 2D case. A "hyperplane" in 2D is just a line, and everything we stated above applies just as well to lines in 2D space - all you have to do is drop N from 3 to 2.
Like this post? Follow me on bluesky for more!