11

I'm trying to write some unit tests and realize I don't know how to compare quaternions. I need to know if two quaternions represent the same orientation (the object would be facing the same way). With a vector like position I'd simply compare the parts and check they are close enough, but for quaternions the values can be very different.

How can I compare two quaternions?

edA-qa mort-ora-y
  • 1,340
  • 4
  • 13
  • 21
  • I'm not sure if it is standard practice, but in e.g. Java and Unity the quaternions are stored as four float values. Simply compare these to eachother as outlined in these posts:

    http://answers.unity3d.com/questions/288338/how-do-i-compare-quaternions.html

    http://stackoverflow.com/questions/5803627/quaternion-comparision

    – Tholle May 15 '14 at 07:19
  • 2
    @Tholle the user is also concerned with the impact of applying the quaternion to transform/rotate a 3D entity (i.e. pose-wise). Two different quaternions can achieve the same rotation (e.g. q and -q). The naive (computationally-wise) way would be to apply both quaternions to the same vector and see if their vector results are different.. – teodron May 15 '14 at 07:52

4 Answers4

16

Just because it hasn't been mentioned. Since quaternions used for spatial orientation are always unit length (or should be), the following will also work.

$$\lvert q_1 \cdot q_2 \rvert > 1 - \epsilon$$

where \$\epsilon\$ (epsilon) is some fudge factor to allow for small errors due to limited floating point precision. If (and only if) both quaternions represent the same orientation then \$q_1 = \pm q_2\$, and thus \$q_1 \cdot q_2 = \pm 1\$. If you want to make sure they're the same rotation (rather than just orientation), then remove the absolute value.

Pikalek
  • 12,372
  • 5
  • 43
  • 51
falstro
  • 1,328
  • 1
  • 9
  • 14
  • @bogglez true. Was hidden in the tl;dr text. :) – falstro May 15 '14 at 16:46
  • +1, pretty elegant and, perhaps even more numerically efficient than my answer (provided SIMD operations are used :) ). – teodron May 16 '14 at 13:25
  • What's the mathematical justification for this? – fabian789 Feb 08 '16 at 15:37
  • "Mathematical" (in quotes cause i m not a mathematician :) ) justification: Two unit length vectors have dot product (a.k.a. inner product) that is 0 if they are vertical to each other, 11=1 if they are pointing exactly the same direction, and 11*cos(phi) in the general case, with phi their angle... – ntg Sep 12 '16 at 13:26
  • this has the effect of throwing away all the sign information. im not sure that is accurate. q = |q| is not always true. – Menace Sep 02 '23 at 18:16
14

If your two quaternions are q1 and q2, they represent the same rotation if either of these two conditions hold:

  1. q1 is component wise approximately equal to q2 OR
  2. q1 is component wise approximately equal to -q2

Knowing this, you can write a fairly simplistic equality tester that suits your goal.

teodron
  • 3,271
  • 20
  • 38
  • 11
    +1, one nitpick though, q and -q represent the same orientation (which was being asked for), but not the same rotation. This is crucial when interpolating. – falstro May 15 '14 at 08:04
  • 2
    @falstro, I think I understand what you mean: the rotation axes are inversed, but the argument angle is also negated between q and -q when represented as an angle-axis rotation operator. So, indeed, technically the effect of these rotations is the same, although the operators are not. And, yes, when SLERPING, one has to make sure q1 and q2 lie on the same hemisphere of the S3 hypersphere in order for the slerp to take the shortest path. – teodron May 15 '14 at 09:30
  • 1
    Exactly, when you execute either rotation, you'll end up with the same orientation, but interpolate it (whether you lerp or slerp or some other fancy interpolation), you'll see it is turning different ways. And yes, the angle argument is negated, but that's the same as 2pi-angle, so it's turning the long way around the negated axes. Sometimes this is what you want though; it's just something to be aware of, q1 dot q2 > 0 results in the short turn, q1 dot q2 < 0 takes the long turn. – falstro May 15 '14 at 09:58
  • is -q1 componentwise negation of q1? – IC_ Dec 09 '21 at 15:37
  • 1
    @IC_ yes that's right. -q is { -q.x, -q.y, -q.z, -q.w } – Wacov Aug 08 '22 at 13:36
2

Quaternions are stored as 4 floats or doubles, often called x, y, z and w, where the first three represent an axis and w the degree of rotation around that axis.

A naive approach would be to just compare those numbers of two quaternions for equality. However, because floating point calculations involve an error, you should at least use an error, often called eps (for epsilon) and compare each component like

    double const eps = 1e-12; // some error threshold
    abs(quat1_x - quat2_x) < eps // similar enough?
    // repeat for other values..

A better test would be to calculate the dot product of the two quaternions and test whether it is close to 1.0. You should look up the equation of quaternions with sin and cos and just dot two quaternions, then you should readily see why this works.

bogglez
  • 462
  • 2
  • 6
  • i dont think this is 100% true. see teodron's answer. This allows the signs to be randomly flipped and still be equal. quaternions come in equiv pairs only. This method allows some false equivalents . – Menace Sep 01 '23 at 20:05
1

Based on all the suggestions to use Dot and eps I found that using (in unity):

Mathf.Approximately(Mathf.Abs(Quaternion.Dot(transform.rotation, to)), 1.0f)

worked well without me having to make a decision for the size of eps.

Sakull284
  • 11
  • 2