Quaternion schema, conversion helpers, normalization helpers, interpolation helpers, and quaternion-derived rotation matrices.


Schema and access model

Fields

Ordinary numeric quaternion construction, casts, arithmetic, normalization, and interpolation return independent values. Component reads are views into entries; a mutable receiver permits writes, and an immutable receiver produces an immutable view.

Access

@

(ordinal quaternion -- ref) Returns a component view.
  • Ordinal must be an Int32. The view is mutable through a mutable entries path and immutable through an immutable path.
  • Unknown indices require uniform entries. Keep runtime indices within range.

!

(value ordinal quaternion --) Writes one component.

fieldCount

(quaternion -- count) Returns the field count of entries as Int32.
  • Ordinary four-component quaternions return 4; malformed/raw wrappers can return other counts.

Constructors and conversions

Quaternion

(entryPrototype -- quaternion) Constructs a quaternion object with four entries created from the supplied prototype.

quaternion

(entries -- quaternion) Constructs a new wrapper around the supplied entries using their construction semantics.
  • The raw-entry form does not validate component count or uniformity. Quaternion arithmetic expects four compatible numeric components in x, y, z, w order.
  • It also accepts a recognized 3×3 matrix of matching real components and converts it to a quaternion. Supply a rotation matrix; orthogonality and normalization are not validated.
  • Other shapes fall back to the raw entries wrapper, not to a general matrix conversion. See the value-ownership rule.

axisAngleQuaternion

(axisAngle -- quaternion) Constructs a quaternion from an axis and angle.
  • Takes (axisX axisY axisZ angle) with compatible real component schemas; angle is in radians.
  • Returns (axisX*sin(angle/2), axisY*sin(angle/2), axisZ*sin(angle/2), cos(angle/2)).
  • Does not normalize the axis. Supply a unit axis for a unit rotation quaternion; use rotationQuaternion for a three-component rotation vector.

identityQuaternion

(entry -- quaternion) Constructs an identity quaternion in the entry schema.
  • Returns components (0,0,0,1).

matrix

(quaternion -- matrix) Converts a quaternion to three rows of three components.
  • Uses the row-vector convention: vector matrix * applies the rotation. A unit quaternion is required for the usual rotation-matrix guarantee; matrix does not normalize it.
  • For components (x,y,z,w), the rows are:
(1-2y^2-2z^2, 2xy+2zw,   2xz-2yw)
(2xy-2zw,    1-2x^2-2z^2, 2yz+2xw)
(2xz+2yw,    2yz-2xw,   1-2x^2-2y^2)

quaternionCast

(quaternion schema -- quaternion) Constructs entries in the supplied numeric target schema.

vector

(quaternion -- vector) Returns an independent component collection.

rotationQuaternion

(rotation -- quaternion)
(rotation threshold -- quaternion)
Converts a three-component rotation vector to a quaternion.
  • The vector's length is the rotation angle in radians. The explicit threshold must be real and is cast to the rotation component schema; the default is 1e-12.
  • Returns identity when squaredLength(rotation) is strictly less than threshold². Otherwise normalizes the vector and uses its length as the axis-angle angle. Equality takes the conversion path.
  • A zero threshold does not protect a zero vector from division by zero.

Algebraic operations

*

(left right -- quaternion) Scales a quaternion or composes two quaternions.
  • Supports (quaternion scalar -- quaternion), (scalar quaternion -- quaternion), and (q0 q1 -- quaternion). A scalar must match the component schema; quaternion operands need compatible matching component schemas. No implicit cross-schema conversion is supplied.
  • Quaternion multiplication composes the row-vector orientations in operand order: q0's rotation followed by q1's. In conventional Hamilton-product notation its components equal q1 ⊗ q0.
  • Follows the value-ownership rule.

+

(left right -- quaternion) Adds quaternion components.
  • Adds components pairwise and requires compatible quaternion component schemas. The result uses that component schema and follows the value-ownership rule.

conj

(quaternion -- quaternion) Returns (x, y, z, -w), the negative of the usual quaternion conjugate.
  • For a unit quaternion it represents the inverse orientation, since opposite quaternion signs represent the same rotation.
  • Follows the value-ownership rule.

dot

(left right -- value) Returns the component dot product.
  • Requires compatible quaternion components and returns the component numeric schema.

squaredLength

(quaternion -- value) Returns the squared Euclidean length in the component numeric schema.

unit

(quaternion -- quaternion) Divides quaternion components by their Euclidean norm.
  • Requires real components and does not guard a zero norm. A runtime zero norm can produce NaN components.

unitChecked

(quaternion -- quaternion) Normalizes or returns identity below the default threshold.
  • Uses threshold 1e-6 cast to the quaternion component schema. See unitCheckedWithThreshold for the comparison and failure rules.

unitCheckedWithThreshold

(quaternion threshold -- quaternion) Normalizes or returns identity using an explicit threshold.
  • Requires real quaternion components and a threshold with the same real schema.
  • Returns identity only when squaredLength is strictly less than threshold²; equality takes normalization. The threshold is squared, so its sign does not change the comparison. Use a positive nonzero threshold to protect a zero quaternion.
  • A runtime zero norm can produce NaN components.

Interpolation and stabilization

Bare Quaternion interpolation requires matching real component schemas; fraction and explicit epsilon must have that schema. Fractions are not clamped to [0,1]; values outside it extrapolate on the interpolating path.

nlerp

(q0 q1 fraction -- quaternion) Linearly blends two quaternions and applies checked normalization.
  • Flips the copied q1 when dot(q0,q1) is negative, linearly blends the entries, and applies unitChecked. Neither input is changed.
  • Follows the value-ownership rule.

slerp

(q0 q1 fraction -- quaternion) Interpolates unit quaternions with spherical weights and default epsilon.
  • Adjusts the sign of q1 when dot(q0,q1) is negative, then uses spherical weights unless the adjusted dot product is greater than 1 − epsilon.
  • Expects unit input quaternions, does not generally normalize its returned quaternion, and uses default epsilon 1e-6 in the fraction schema.
  • Follows the value-ownership rule.

Known issue: for nearly parallel inputs (sign-adjusted dot above 1 − epsilon) the sign-adjusted second quaternion is returned without interpolation for every fraction, so fraction 0 need not return the first.

slerpWithEpsilon

(q0 q1 fraction epsilon -- quaternion) Interpolates unit quaternions with an explicit epsilon.
  • Uses the same sign choice and spherical path as slerp. The explicit epsilon must match the real component schema, and positive epsilon is required for ordinary use.
  • With identical inputs and epsilon 0, the spherical-weight calculation can produce NaN. The near-dot behavior is described in the slerp known-issue note.
  • Follows the value-ownership rule.

Examples

Schema access

"Quaternion.fieldCount"         use
"Quaternion.identityQuaternion" use
"control"                       use

{} () {} [
  Real32 identityQuaternion fieldCount printStack _:;
] "main" exportFunction

Expected Output During Compilation

4

Zero-angle construction

"Quaternion.axisAngleQuaternion" use
"control"                        use

{} () {} [
  (0.0r32 0.0r32 1.0r32 0.0r32) axisAngleQuaternion printStack _:;
] "main" exportFunction

Expected Output During Compilation

{
  QUATERNION: ();
  entries: (0.0r32 0.0r32 0.0r32 1.0r32);
}

Matrix conversion

"Quaternion.identityQuaternion" use
"Quaternion.matrix"             use
"control"                       use

{} () {} [
  q: Real32 identityQuaternion;
  q matrix printStack _:;
] "main" exportFunction

Expected Output During Compilation

((1.0r32 0.0r32 0.0r32) (0.0r32 1.0r32 0.0r32) (0.0r32 0.0r32 1.0r32))

Checked normalization fallback

"Quaternion.quaternion"  use
"Quaternion.unitChecked" use
"control"                use

{} () {} [
  q: (0.0r32 0.0r32 0.0r32 0.0r32) quaternion;
  q unitChecked printStack _:;
] "main" exportFunction

Expected Output During Compilation

{
  QUATERNION: ();
  entries: (0.0r32 0.0r32 0.0r32 1.0r32);
}

Runtime matrix check

"Quaternion.identityQuaternion" use
"Quaternion.matrix"             use
"String"                        use
"algebra"                       use
"control"                       use

{} Int32 {} [
  q: Real32 identityQuaternion;
  m: q matrix;
  expected: ((1.0r32 0.0r32 0.0r32) (0.0r32 1.0r32 0.0r32) (0.0r32 0.0r32 1.0r32));
  m expected = print
  LF print
  0
] "main" exportFunction

Expected Output

TRUE

See also