### Safe vector angle calculations

Posted:

**Sun Apr 03, 2022 8:21 am**I'm sure we've all been bitten by

For two unit vectors
(

This is perfectly safe at any angle, and can never produce a

If either
Of course, the obvious optimization of caching

There are only two disadvantages to using this: it's a little slower (

Some nice bonus information...

For unit vectors,

Now, this is very handy when it comes to finding the quaternion describing the rotation between the two vectors. When I implemented the TINU (There Is No Up) mod for KSP, I discovered that Unity's

I'll leave the derivation as an exercise (hint, it takes advantage of trig identities), but this is taken directly from the code in TINU:
Only an exact 180 degree rotation (ie,

**acos(x)**or**asin(x)**producing**nan**(or an exception) despite efforts to ensure**x**is in the -1..1 range. I learned a very nice bit of math while I was off in KSP land. Don't use**acos**or**asin**. Use**atan**, or even better,**atan2**. (Indirect thanks to William Kahan, more direct thanks to "egg" (KSP modder (Principia mod)).For two unit vectors

**a**and**b**:Code: Select all

`ang = 2 * atan2 (mag(a - b), mag(a + b);// use 360/pi for degrees`

**mag(v)**is the length of**v**)This is perfectly safe at any angle, and can never produce a

**nan**unless either**a**or**b**has a**nan**in a component.If either

**a**or**b**may be a non-unit vector (even zero!!!), then with a slight modification the angle can still be safely determined:Code: Select all

`ang = 2 * atan2(mag(mag(b)*a - mag(a)*b), mag(mag(b)*a + mag(a)*b));`

**mag(b)*a**and**mag(a)*b**can be quite helpful.There are only two disadvantages to using this: it's a little slower (

**atan**and thus**atan2**(which is just a very smart wrapper for**atan**) is inherently slower than**acos**or**asin**), and you lose the direction of the angle. However, this can be retrieved by finding the cross-product of**a**and**b**and dotting that with a reference direction to get the sign of the angle.Some nice bonus information...

For unit vectors,

**mag(a - b) == 2*sin(ang(a,b)/2)**, ie, twice the**sin**of the half-angle between**a**and**b**, and**mag(a + b) == 2*cos(ang(a,b)/2)**(twice the**cos**of the half-angle)Now, this is very handy when it comes to finding the quaternion describing the rotation between the two vectors. When I implemented the TINU (There Is No Up) mod for KSP, I discovered that Unity's

**Quaternion.FromToRotation**was not usable for very small angles (think per-frame rotation while in low orbit, worse in high orbit). The reason for this is, I assume, due to using epsilons and guarding against going outside the -1..1 range for**acos**.I'll leave the derivation as an exercise (hint, it takes advantage of trig identities), but this is taken directly from the code in TINU:

Code: Select all

```
Quaternion fromtorot(Vector3 a, Vector3 b)
{
float ma = a.magnitude;
float mb = b.magnitude;
Vector3 mb_a = mb * a;
Vector3 ma_b = ma * b;
float den = 2 * ma * mb;
float mba_mab = (mb_a + ma_b).magnitude;
float c = mba_mab / den;
Vector3 v = Vector3.Cross (a, b) / mba_mab;
return new Quaternion(v.x, v.y, v.z, c);
}
```

**a**and**b**are anti-parallel) or either vector is invalid (**nan**,**inf**,**0**) can produce a bogus quaternion. Also, the code is chirality agnostic.