std/linear/quaternion
std/linear/src/quaternion.trb
Quaternion, a rotation of space that composes and interpolates without shearing and without the gimbal lock that
three angles in a row have.
It is four numbers: the axis of the rotation, scaled by the sine of half the angle, and the cosine of half the angle.
Nothing in the library asks a caller to know that; Quaternion.rotation builds one from an axis and an Angle, and
Quaternion.applied turns a point with it.
type Quaternion
type Quaternion<Scalar: Real = Float> with Multiply, Negate
A rotation of space, as four numbers.
The sense is right-handed: a positive angle around unitZ takes unitX towards unitY, which is the same sense
Angle and Matrix3.rotationAroundZ use.
Examples
const turn = Quaternion.rotation around: Vector3(0.0, 0.0, 1.0), by: Angle.degrees(90.0)
print turn.applied(to: Vector3(1.0, 0.0, 0.0)).isCloseTo(Vector3(0.0, 1.0, 0.0), tolerance: 0.0001)
Pitfalls
- Only a quaternion of length one is a rotation. Every constructor here answers one, and composing two of them keeps
the length - but arithmetic that drifts is put back with
Quaternion.normalized. - A rotation and its negation turn space the same way, so two quaternions that are equal as rotations can compare unequal. Compare what they do (apply both to the axes) rather than the four numbers.
Open
Quaternion.interpolatedtakes the straight path between the two and puts the length back, rather than the constant-speed path along the sphere. The two agree at both ends and differ in the middle, and the constant-speed form needs an arc cosine whose accuracy near a zero angle is worth measuring before it is written.
Related
field x
x: Scalar
The first component of the axis part.
field y
y: Scalar
The second component of the axis part.
field z
z: Scalar
The third component of the axis part.
field w
w: Scalar
The cosine of half the angle.
const identity
static identity: Quaternion<Scalar> = Quaternion Scalar.zero, Scalar.zero, Scalar.zero, Scalar.one
No rotation, over whichever scalar is asked for: Quaternion<Fixed>.identity.
fn rotation
static fn rotation(around: Vector3<Scalar>, by: Angle<Scalar>): Quaternion<Scalar>
The rotation by that angle around that axis. The axis is normalized first, so it may have any length; a zero axis answers no rotation at all.
print Quaternion.rotation(around: Vector3(0.0, 1.0, 0.0), by: Angle.degrees(180.0)).w
fn axisPart
fn axisPart(): Vector3<Scalar>
The axis part, without the fourth number.
fn conjugate
fn conjugate(): Quaternion<Scalar>
The rotation that undoes this one, for a quaternion of length one.
fn negate
fn negate(): Quaternion<Scalar>
Every number with its sign flipped, which turns space the same way and is therefore not the inverse.
fn lengthSquared
fn lengthSquared(): Scalar
The sum of the four squares, which is one for every rotation.
fn length
fn length(): Scalar
The length over all four numbers.
fn normalized
fn normalized(): Quaternion<Scalar>
The same rotation with the length put back to one. A zero quaternion answers no rotation.
fn multiply
fn multiply(other: Quaternion<Scalar>): Quaternion<Scalar>
The composition: self after other, the same order Matrix3 composes in.
fn applied
fn applied(to: Vector3<Scalar>): Vector3<Scalar>
The point, turned by the rotation.
const turn = Quaternion.rotation around: Vector3(0.0, 0.0, 1.0), by: Angle.degrees(90.0)
print turn.applied(to: Vector3(2.0, 0.0, 0.0))
fn toMatrix3
fn toMatrix3(): Matrix3<Scalar>
The same rotation as a matrix, which is the form a shader and a scene graph want.
fn interpolated
fn interpolated(toward: Quaternion<Scalar>, by: Scalar): Quaternion<Scalar>
The rotation factor of the way from here to there, along the straight line between the four numbers and then
back onto the sphere. It takes the shorter of the two ways around, which is what an animation means by it.
fn dot
fn dot(other: Quaternion<Scalar>): Scalar
The dot product of the four numbers: the cosine of half the rotation between the two.
fn isCloseTo
fn isCloseTo(other: Quaternion<Scalar>, tolerance: Scalar): Bool
Whether every number is within tolerance of the other quaternion's.