# Euler adjustments between two quaternions

I have two quaternions, q1 and q2. If my object's current rotation is at q1, but I need to get it to q2, what would be the process to figure out how much rotation I apply to x, y, and z in order to get there?

In this example, x=right, y=up, z=forward

I've tried getting the delta between the two quaternions and unwrapping that into Eulers and moving the x, y, z the amount of the unwraped Vector3f, but that does not seem to give the correct values. Current implementation in pseudo code:

var dQuat = Quaternion.Inverse(prevRotation) * target.rotation;
dChange = dQuat.eulerAngles;


This approach gives me only positive changes. If I rotate forward on x, I get positive lower numbers and if I rotate backwards on x, I get larger positive numbers.

I'm looking for, in order to get to q2 from q1, rotate n degrees along your x, y, z...

Thanks in advance for any help!

• When you rotate "backwards" on any axis are the values greater than 180? Backwards being where you would expect negative numbers. Oct 8, 2015 at 17:38
• why do you need the euler? Oct 8, 2015 at 18:46
• @ConnorHollis correct. Normally in the 300+ range Oct 8, 2015 at 19:26
• @ratchetfreak because I'm physically moving motors on an x, y, and/or z axis. Oct 8, 2015 at 19:27
• @nathansizemore if the value is over 180 just subtract 360 and see if that's what you want. That should (if I am getting what you are describing correctly) give you a positive 0 to 180 range and a negative 0 to -180 range. Oct 8, 2015 at 20:03

Sounds like you are working with step motors which will take a rotation along a fixed axis. Not an answer to your question but an alternative I have used successfully: Work with spherical coordinates (pitch and yaw) to match your two motors on the x and y axis? Keep your direction heading as a vector (pointing in the direction you are gazing). BTW, a quaternion is a gaze vector + rotation around the gaze vector. If you do not have a step motor for the roll around the gaze, you may ignore that anyways. You have +z as forward, so you are using left handed math presumably. I have done the same and display the results using DirectX which uses left handed math. Below is sample code to calculate pitch and yaw from a gaze vector. This gives two Eugler angles around two fixed axis 0 to 360 degrees. Perform this once on your current gaze vector and again on the "to be gaze" vector, and subtract them. Dive by the degree of each motor's step, and that and its sign will give you the proper motor rotation. If you do not have position feedback, then calculate your final gaze vector using your degrees per step intervals so it stay in sync with your motor's true position after every rotation and just use the code snippet below to calculate the "to be gaze" vector.

void CalculatePitchYaw(
XMFLOAT3 &vectorInOut, // Input: vector direction in x, y, z; Output: x & z snapped to axis near zero & normalized.
float &pitchRadiansOut, // Output: Pitch 0 to XM_2PI
float &yawRadiansOut, // Output: Yaw 0 to XM_2PI
const bool rhs) // set to false if using left hand system vector math
{
XMVECTOR dir = XMVector3Normalize(XMLoadFloat3(&vectorInOut)); // unit vector for direction only
XMFLOAT3 vec;
XMStoreFloat3(&vec, dir);

const float nearZero = 0.0005; // 1/12500.f increments of a circle (radians); // not too small as we are dividing and using atan2f.  If more accuracy is needed, drop this tolerance and use atan2 (doubles) instead.

// Calculate yaw & pitch
// yaw (bearing in XZ plane)
if (fabsf(vec.x) <= nearZero) // near zero x-axis
{
vec.x = 0.0f;  // treat as only along the z-axis
if ((vec.z > 0.0f && rhs) || (vec.z < 0.0f && !rhs)) yawRadiansOut = XM_PI; // 180 deg
else yawRadiansOut = 0; // 0 deg
}
else if (fabsf(vec.z) <= nearZero) // near zero z-axis
{
vec.z = 0.0f; // treat as only along the x-axis
if (vec.x > 0.0f) yawRadiansOut = XM_PIDIV2; // 90 deg ; right of z-axis
else yawRadiansOut = XM_2PI - XM_PIDIV2; // 270 deg ; left of z-axis
}
else yawRadiansOut = atan2f(vec.x, vec.z);// rotation about the y-axis; neither near x nor z axis

// pitch (bearing in YZ plane)
vec.z = fabsf(vec.z);
vec.x = fabsf(vec.x);
if (vec.x > vec.z) vec.z = vec.x;

vectorInOut = vec;