Extending type-safe physical values to multiple dimensions

In this recent post we saw how we can represent the physical units of length, speed, acceleration, and time using our own types to only allow for type-safe operations between them, and find errors and bugs at compile time.

Today we will expand these ideas to more than one dimension, with the example of two dimensional types.

One-dimensional recap

The types we implemented in the last post are Unit, Speed, Acceleration, Timespan and Instant.

Apart from Instant these all form one-dimensional vector spaces. Instant is special since its semantic meaning is different from the other. By splitting it from Timespan we split the concepts of absolute and relative time. While this is not necessary to make the mathematics work out, it is an additional type check the compiler can do for us, since the two should not be used interchangeably.

We saw that we could have done the same with Unit, splitting it into an absolute position, and a relative difference. In fact, the same could be done with Speed and Acceleration as well. However, we did and are not doing so, since the usage for these extra types would be limited.

I argue that the effort and complication of having so many extra types does not outweigh the advantages gained. That being said, I would be curious to hear arguments for splitting these types.

Two dimensional physical types

When adding further dimensions, what we mean is adding spatial dimensions. We are perfectly happy with sticking with a single dimension of time here.

That means that our time related types are just fine the way they are.

What we want to look at is the remaining types. We want to represent the same concepts in two dimensions.

So let us start with the following list of types: Unit2, Speed2, Acceleration2.

This works, however, the names of Unit2 and Speed2 are somewhat awkward. Let us rename the latter to Velocity2.

Unlike in the one-dimensional set of types, the concepts of position and difference between positions are quite different in two dimensions. I argue that this is a difference worth splitting the Unit2 type over. In an actual game or application we will deal with a lot of absolute positions, but also with a lot of differences between them. We want to make sure that the two cannot be confused.

Let us call these new types Position2 and Difference2.

Operations within and between types

Our full list of new types is now Position2, Difference2, Velocity2, and Acceleration2.

Apart from Position2 with its special absolute nature (just like Instant) these are again vector fields, just in two dimensions.

That means we can apply all the usual operations like addition, subtraction and scaling.

The interaction with Position2 is more limited. We can merely subtract two of them to receive the difference between them, or we can add a Difference2 to receive a new position.

When we add our Timespan type to the mix, we can however also use multiplication with and division by it to integrate and differentiate between the other types.

The full list of operations that we define is as follows.

// Vector field operations for difference2, velocity2 and acceleration2
// (example: difference2)
difference2 + difference2 = difference2
difference2 - difference2 = difference2
difference2 * scalar = difference2
difference2 / scalar = difference2

// interactions with position2
position2 - position2 = difference2
position2 + difference2 = position2
difference2 - difference2 = position2

// integration
acceleration2 * timespan = velocity2
velocity2 * timespan = difference2

// differentiation
difference2 / timespan = velocity2
velocity2 / timespan - acceleartion2

There are a couple of other operations we could add, but these are all we need in most cases. They allow us to do all the usual operations of calculating difference between different objects, apply forces as accelerations, and integrate velocities to calculate movement per frame.

For a full implementation feel free to checkout the same classes discussed here on GitHub.

Conclusions

Today we took a look at how to extend the idea of representing physical quantities with concrete type-safe types to two dimensions.

If you found this post interesting, make sure to share it on your favourite social media.

Next week we will take a look at how we can further work with these types and represent the orientation and rotations of our game objects as well.

Until then, make sure to leave a message below if you have any questions or comments.

Enjoy the pixels!

Leave a Reply