Tips for Managing Multiple Coordinate Systems

Original Author: James Podesta

Most programmers with any experience in 3D will have dealt with cartesian coordinates, in what we would call World Space. Graphics programmers will certainly have had a lot experience in homogeonous coordinates as well as View space and Screen space. Anyone dealing with animation or collision will have spent a lot of time in local space. All of these are different ways that a single absolute position in space can be represented. However, these are all taken at different stages in a pipeline and have very specific uses. Where I find it can get quite complicated is if you have multiple co-ordinate systems at the same level which only serve to show the same absolute co-ordinates from a different mathematical perspective.

My latest contract has me working in flight simulator territory. This now introduces geocentric coordinates as well as lon/lat/alt co-ordinates on top of the usualy world space which is the core of the rendering pipeline. Geocentric co-ordinates are basically a typical cartesian system (X,Y,Z) but where (0,0,0) represents the centre of the planet and the Y axis points to the North Pole. Orientation also has several representations in the application. There is a geocentric representation which is the transform from the geocentric identity as well as the render world space orientation which is the more traditional “local to world” transform in 3d applications. All these transformations have the potential to make any code very confusing indeed, as I soon discovered coming onto the project. I spent the next few weeks researching the co-ordinate systems and coming up with some modifications to the code base to make it readable to myself and others.

Understand the co-ordinate systems you will be working in

The first thing you need to do is actually understand how the co-ordinate system works. For positional systems, this means understand exactly what (0,0,0) represents (assuming a 3 coordinate system of course). In some coordinate systems (0,0,0) might not represent a static position in space. Be aware of what direction positive is on each of the coordinates.

Some coordinates may represent curves through space. For instance, with lat/lon/alt coordinate systems, lattitude lines curved around the earth. This is significant if you are comparing distances between points in one space to differences between the same points in another space.

Understand the scale of the coordinates. Hopefully most cartesian systems will be in metres, but I’ve seen a few in centimetres. For lat/lon/alt, it is good to have a feel for how many metres a degree of longitude is. I see this as part of the classic mantra of “know your data”.

For orientation systems, understand exactly what it means to give one of your game objects an identity orientation in this coordinate system. Which direction will it face. I like to visualize the x,y,z vectors of a matrix at identity and see in which direction each axis represents with respect to an identity oriented game object. Understand what direction pitch, yaw and roll travel in. Understand what a cross product will give in this coordinate system. It only takes a few experiments to get data on all these and its generally not safe to assume that the maths libraries will do exactly as you expect if you didn’t write them yourself.

Understand what each coordinate systems strengths are

Each coordinate system is there for a reason, so learn what that reason is. If there is NO reason, then you would shouldn’t be using that coordinate system and complicating your code unnecessarily. For my project, all our coordinate systems were mandatory due to other software we were interfacing with.

Each coordinate system is particularly good at certain maths, and weak at others. Geocentric is a nice simple cartesian system in metres, but the concept of “up” varies with your location so heightmap patches are expensive to apply. Longitude/Lattitude/Altitude is convenient for heightmaps since “up” is represented by “altitude” and 0 is at the surface of the planet. It’s weaknesses are that it is in degrees (instead of metres) and the first 2 coordinates represent curved space making distance and angle calculations very inaccurate when the points are far apart.

Write simple explicit conversion routines for going between coordinate systems

Invent a unique string identifier for each coordinate system. This allows you to have consistent transformation functions between each space. While implicit transformations would be convenient and easy to implement, it is important for code readability to see clearly when data is transformed. For my project I have the 3 systems I need to consistently transform between. Geocentric (geo), Lon/Lat/Alt (LLA) and Local Open GL coordinates (Local). When I came onto the project, there was no consistent and easy way to transform between coordinates.   Some transformations used methods of a class, others used static functions and others were a composite of functions. Worse still, the naming of the methods had no obvious link to the concept that you where trying to transform from one space to another.

I’ve now wrapped all the various transformation methods with simple consistent helper functions.

vector3 PositionGeoToLocal( const vector3 &vectorGeo )
  vectorLLA PositionGeoToLLA( const vector3 &vectorGeo )
  vector3 PositionLLAToGeo( const vectorLLA &vectorLLA )
  vector3 PositionLLAToLocal( const vectorLLA &vectorLLA )
  vector3 PositionLocalToGeo( const vector3 &vectorLocal )
  vectorLLA PositionLocalToLLA( const vector3 &vectorLocal )
  quaternion OrientationGeoToLocal( const quaternion &orientGeo )
  quaternion OrientationLocalToGeo( const quaternion &orientLocal )

Use a variable naming convention for your coordinates

Since you may different coordinate systems interleaved through a single block of maths, it can help with code readability to use a naming convention that identifies the coordinate system you are using. My prefered method is a small postfix on the variables, but a prefix would work just as well.

Having different classes for each representation helps the compiler spot any misuse of variables but it doesn’t help the clarity of the code.

Converting Velocities Safely

Velocities and directions are a little trickier to convert since they can depend on what position they are taken from. The simple trick here is to convert the current position, and calculate and convert the current position plus the velocity. Then if you take a difference between those positions, you get the converted velocity.

vectorLLA positionLLA = PositionGeoToLLA( positionGeo )
  vectorLLA velocityLLA = PositionGeoToLLA( positionGeo + velocityGeo ) - positionLLA;

It important to realise here that applying the same velocity in LLA space will not give you the same results as applying it in a cartesian coordinate system.

Other interesting uses of curved space

Something I’ve done on a couple of projects now is to use a 2d coordinate system that represents curved space. When coordinates a transformd into their cartesian counterpart for rendering,  space is effectively warped giving you a more interesting world to move in. For instance, a simple old school 2d game can bend around 3d space without complicating the actual movement or physics maths since those are done as simple x,y maths in curved space.

On my current game, Magelore, I use a curved coordinate system to add some noise to what would have been a very square-edged tile system. All game code is just done in a simple x,y grid,  but when transforming from grid space to cartesian space, it all gets warped somewhat.