Stannum/blog/

Rethinking geometry libraries

2015-09-10 Permalink

You may think that the following are obviously true, or you may find them controversial. Yet the fact that I’ve seen these issues in real code and that they caused much pain makes this, nevertheless, important.

So here we go.

Vectors

Boxes (axis aligned)

Offender: Qt.

Order-theoretic way

Rather than starting from their geometric meaning as special subsets of ℝn, start with the order-theoretic notion of the lattice (ℝn×ℝn, contains−1) where:

The corresponding meet and join operators are

The geometric interpretation of the box x is given by

Defer the geometric interpretation until necessary. It is implied that:

Rotation matrices

class Matrix3d {
public:
	double mat[3][3];
	/* ... */
};
class OrthogonalMatrix : public Matrix3d { /* ... */ };
class RotationMatrix : public OrthogonalMatrix { /* ... */ };

This code is real. Do you see the problem? This is much like the Circle And Ellipse Problem. All those functions working on Matrix3d can easily invalidate the assumption that RotationMatrix represents a rotation, even remotely. Separating RotationMatrix from Matrix3d won’t save it from being ruined by floating point operations anyway.

For rotations, either use a matrix with a code prepared to digest any matrix fed in, or a quaternion.[5] Don’t try to solve this by hiding the representation. Matrices and quaternions have different numerical properties, and such properties will leak through the interfaces, much like operations over std::vector and std::list have different guarantees. If you just want to use RotationMatrix for self-documentary purpose, then a simple old typedef would do.

By the way, the use of OrthogonalMatrix was virtually null.

Footnotes

  1. For dimensions ≥ 2.
  2. Liberate operators movement.
  3. Here min and max are elementwise.
  4. The opposite is true if x and y aren’t empty.
  5. Or a so(3) vector for infinitesimal rotations.