Maths - Conversion Axis-Angle to Euler

Equations

heading = atan2(y * sin(angle)- x * z * (1 - cos(angle)) , 1 - (y2 + z2 ) * (1 - cos(angle)))
attitude = asin(x * y * (1 - cos(angle)) + z * sin(angle))
bank = atan2(x * sin(angle)-y * z * (1 - cos(angle)) , 1 - (x2 + z2) * (1 - cos(angle)))

except at the singularities, straight up:
heading = 2 * atan2(x * sin(angle/2),cos(angle/2))
bank = 0
straight down:
heading = -2 * atan2(x * sin(angle/2),cos(angle/2))
bank = 0

Issues

If you have a different result from that shown on this page it may be that you are using different standards, I have tried to keep the standards consistant accross this site and I have tried to define the standards that I am using here. One of these standards is that the order that the euler rotations are applied is 'NASA standard aeroplane' it uses a slightly different coordinate definition from VRML (z and y axis swapped). Also when working with aeroplanes we often work in terms of the position of external objects relative to the aircraft (i.e. the inverse of its position transform as explained here). therefore to get the expression normally used with NASA aeroplane we invert all inputs (change sign of every term with odd number of sine terms) invert output (conjugate quaternion) swap z and y for inputs (swap z and y columns) swap z and y for outputs (swap z and y rows). In the case of aircraft it can make sense to work in terms of the local frame of reference of the aircraft looking out, I have a version of this page that does that here, but be careful as this will no longer be compatible with the rest of this site.

However if you have checked these things and you still have a discrepency then I have probably made an error so please let me know here.

Code

public void toEuler(double x,double y,double z,double angle) {
	double s=Math.sin(angle);
	double c=Math.cos(angle);
	double t=1-c;
	//  if axis is not already normalised then uncomment this
	// double magnitude = Math.sqrt(x*x + y*y + z*z);
	// if (magnitude==0) throw error;
	// x /= magnitude;
	// y /= magnitude;
	// z /= magnitude;
	if ((x*y*t + z*s) > 0.998) { // north pole singularity detected
		heading = 2*atan2(x*Math.sin(angle/2),Math.cos(angle/2));
		attitude = Math.PI/2;
		bank = 0;
		return;
	}
	if ((x*y*t + z*s) < -0.998) { // south pole singularity detected
		heading = -2*atan2(x*Math.sin(angle/2),Math.cos(angle/2));
		attitude = -Math.PI/2;
		bank = 0;
		return;
	}
	heading = Math.atan2(y * s- x * z * t , 1 - (y*y+ z*z ) * t);
	attitude = Math.asin(x * y * t + z * s) ;
	bank = Math.atan2(x * s - y * z * t , 1 - (x*x + z*z) * t);
}

Derivation of Equations

Euler angles represent 3 rotations about the x,y and z axis in some given order. We can replace any sequence of rotations by one single rotation about some axis.

We need to be very careful about using Euler Angles and it is best to work in terms of quaternions or matricies whenever we can. As explained in euler section there are different types of Euler angles and the result will depend on the Euler definition used. Also the following calculations use a lot of trig functions and therefor will use a lot of CPU time. The accuracy may be low, specially near the singularity of the Euler system being used.

With these warnings in mind here is the calculation.

Euler can be defined in terms of a quaternion as shown here.

heading = atan2(2*qy*qw-2*qx*qz , 1 - 2*qy2 - 2*qz2)
attitude = asin(2*qx*qy + 2*qz*qw)
bank = atan2(2*qx*qw-2*qy*qz , 1 - 2*qx2 - 2*qz2)

This quaternion can be defined in terms of axis-angle as shown here.

qx = x * sin(angle/2)
qy = y * sin(angle/2)
qz = z * sin(angle/2)
qw = cos(angle/2)

So working out some products gives:

qx*qw = x * sin(angle/2) * cos(angle/2) = 0.5 * x * sin(angle) // using trig identity: sin(angle) = 2 sin(angle/2) cos(angle/2) from here

qy*qw = y * sin(angle/2) * cos(angle/2) = 0.5 * y * sin(angle)

qz*qw = z * sin(angle/2) * cos(angle/2) = 0.5 * z * sin(angle)

qx*qy = x * y * sin2(angle/2) = x * y * (0.5 - 0.5*cos(angle)) // using trig identity cos(angle) = 1 - 2 sin2(angle/2) from here

qy*qz = y * z * sin2(angle/2) = y * z * (0.5 - 0.5*cos(angle))

qx*qz = x * z * sin2(angle/2) = x * z * (0.5 - 0.5*cos(angle))

qx2 = x2 * sin2(angle/2) = x2 * (0.5 - 0.5*cos(angle))

qy2 = y2 * sin2(angle/2) = y2 * (0.5 - 0.5*cos(angle))

qz2 = z2 * sin2(angle/2) = z2 * (0.5 - 0.5*cos(angle))

qw2 =cos2(angle/2) = 0.5 * (cos(angle)+1) // using trig identity cos(2A) = 2 cos2(A) - 1 from here

So substituting in euler equations gives:

heading = atan2(2*qy*qw-2*qx*qz , 1 - 2*qy2 - 2*qz2)
attitude = asin(2*qx*qy + 2*qz*qw)
bank = atan2(2*qx*qw-2*qy*qz , 1 - 2*qx2 - 2*qz2)

heading = atan2(2*0.5 * y * sin(angle)-2*x * z * (0.5 - 0.5*cos(angle)) , 1 - 2*y2 * (0.5 - 0.5*cos(angle)) - 2*z2 * (0.5 - 0.5*cos(angle)))
attitude = asin(2*x * y * (0.5 - 0.5*cos(angle)) + 2*0.5 * z * sin(angle))
bank = atan2(2*0.5 * x * sin(angle)-2*y * z * (0.5 - 0.5*cos(angle)) , 1 - 2*x2 * (0.5 - 0.5*cos(angle)) - 2*z2 * (0.5 - 0.5*cos(angle)))

heading = atan2(y * sin(angle)- x * z * (1 - cos(angle)) , 1 - y2 * (1 - cos(angle)) - z2 * (1 - cos(angle)))
attitude = asin(x * y * (1 - cos(angle)) + z * sin(angle))
bank = atan2(x * sin(angle)-y * z * (1 - cos(angle)) , 1 - x2 * (1 - cos(angle)) - z2 * (1 - cos(angle)))

heading = atan2(y * sin(angle)- x * z * (1 - cos(angle)) , 1 - (y2 + z2 ) * (1 - cos(angle)))
attitude = asin(x * y * (1 - cos(angle)) + z * sin(angle))
bank = atan2(x * sin(angle)-y * z * (1 - cos(angle)) , 1 - (x2 + z2) * (1 - cos(angle)))

singularities

On the quaternion to euler page that except when we have a singularity when we are going straight up or down

this happens at qx*qy + qz*qw = 0.5 and qx*qy + qz*qw = -0.5

north pole south pole

qx*qy + qz*qw = 0.5

x * y * (0.5 - 0.5*cos(θ)) + 0.5 * z * sin(θ) = 0.5

x * y * (1 - cos(θ)) + z * sin(θ) = 1

qx*qy + qz*qw = -0.5
x * y * (0.5 - 0.5*cos(θ)) + 0.5 * z * sin(θ) = -0.5

x * y * (1 - cos(θ)) + z * sin(θ) = -1

at this point:

heading = 2 * atan2(qx,qw)
= 2 * atan2(x * sin(θ/2),cos(θ/2))

bank = 0

at this point:

heading = -2 * atan2(qx,qw)
= -2 * atan2(x * sin(θ/2),cos(θ/2))

bank = 0

where:

In order to try to get an intuative understanding of the singularities involved in converting other representations of 3D rotations to Euler angles it may help to look at the way we project the surface of a sphere onto a 2 dimensional map. This is a different case and it only involves two angles, latitude and longitude, but this simpler example may show the principles. This analogy is explained in more detail on this page.

At the north and south poles longitude does not matter so if we are converting some other description of north pole to latitude, longitude it might give any value for longitude, for example, infinity. So we have to be very careful at these points.

earth projection

Similarly we can map Euler angles to quaternions (4 dimensional hypersphere). This maps a one dimensional space (rotations around 0,1,0 axis) to a two dimensional plane in Euler terms. This is where attitude = 90° and heading, bank vary:

north pole

On this plane lines of common orientation are diagonal lines, that is rotation around 0,1,0 axis are given by angle = heading+bank.

Similarly for the south pole.

Example

we take the 90 degree rotation from this: to this:

As shown here the axis angle for this rotation is:

angle = 90 degrees
axis = 1,0,0

So using the above result:

heading = atan2(y * sin(angle)- x * z * (1 - cos(angle)) , 1 - (y2 + z2 ) * (1 - cos(angle)))
attitude = asin(x * y * (1 - cos(angle)) + z * sin(angle))
bank = atan2(x * sin(angle)-y * z * (1 - cos(angle)) , 1 - (x2 + z2) * (1 - cos(angle)))

we substitute our axis angle: angle=90 degrees, sin(angle) =1, 1 - cos(angle) =1, x=1, y=0, z=0

heading = atan2(0 / 1 )
attitude = asin(0 )
bank = atan2(1 / 0)

which gives:

heading = 0 degrees
bank = 90 degrees (since the tangent of 90 degrees is infinity)
attitude = 0 degrees

So this gives the correct result, it is banking by 90 degrees, but we have to be very careful about the following issues:

Angle Calculator and Further examples

I have put a java applet here which allows the values to be entered and the converted values shown along with a graphical representation of the orientation.

Also further examples in 90 degree steps here


metadata block
see also:

 

Correspondence about this page

Book Shop - Further reading.

Where I can, I have put links to Amazon for books that are relevant to the subject, click on the appropriate country flag to get more details of the book or to buy it from them.

cover Game Design for Teens.

This site may have errors. Don't use for critical systems.

Copyright (c) 1998-2023 Martin John Baker - All rights reserved - privacy policy.