Reference

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.interpolated takes 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

  • Matrix3 - the same rotation as a matrix, which is what a shader wants.
  • Angle - what a rotation is measured in.

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.