Search documentation of bb

# BB.Math.Quaternion (bb v0.17.0)

Copy Markdown View Source

Unit quaternion for 3D rotations, backed by an Nx tensor.

Quaternions are stored in WXYZ order (scalar first): `[w, x, y, z]`. All math operations use Nx for consistent performance and potential GPU acceleration.

All operations return normalised unit quaternions suitable for representing rotations. The underlying tensor is always `{4}` shape with `:f64` type.

## Examples

    iex> q = BB.Math.Quaternion.identity()
    iex> BB.Math.Quaternion.w(q)
    1.0

    iex> q1 = BB.Math.Quaternion.from_axis_angle(BB.Math.Vec3.unit_z(), :math.pi() / 2)
    iex> q2 = BB.Math.Quaternion.from_axis_angle(BB.Math.Vec3.unit_z(), :math.pi() / 2)
    iex> q3 = BB.Math.Quaternion.multiply(q1, q2)
    iex> BB.Math.Quaternion.angular_distance(q3, BB.Math.Quaternion.from_axis_angle(BB.Math.Vec3.unit_z(), :math.pi()))
    0.0

## Summary

### Types

t()

### Functions

angular_distance(quaternion1, quaternion2)

Computes the angular distance between two quaternions in radians.

conjugate(quaternion)

Returns the conjugate of a quaternion.

from_axis_angle(vec3, angle)

Creates a quaternion from an axis-angle representation.

from_euler(roll, pitch, yaw, order \\ :xyz)

Creates a quaternion from Euler angles (roll, pitch, yaw).

from_list(list)

Creates from a list in WXYZ order.

from_rotation_matrix(matrix)

Creates a quaternion from a 3x3 rotation matrix.

from_tensor(tensor)

Creates a quaternion from an existing `{4}` tensor.

from_two_vectors(vec31, vec32)

Creates a quaternion representing the shortest rotation from one vector to another.

from_xyzw_list(list)

Creates from a list in XYZW order (for ROS/external system compatibility).

identity()

Returns the identity quaternion (no rotation).

identity_tensor()

Returns an identity quaternion as a raw tensor (for batch operations).

inverse(q)

Returns the inverse of a quaternion.

multiply(quaternion1, quaternion2)

Multiplies two quaternions (Hamilton product).

new(w, x, y, z)

Creates a new quaternion from w, x, y, z components.

normalise(quaternion)

Normalises a quaternion to unit length.

rotate_vector(quaternion, vec3)

Rotates a 3D vector by a quaternion.

slerp(quaternion1, quaternion2, t)

Spherical linear interpolation between two quaternions.

tensor(quaternion)

Returns the underlying `{4}` tensor.

to_axis_angle(quaternion)

Converts a quaternion to axis-angle representation.

to_euler(q, order \\ :xyz)

Converts a quaternion to Euler angles (roll, pitch, yaw).

to_list(quaternion)

Converts to a list in WXYZ order.

to_rotation_matrix(quaternion)

Converts a quaternion to a 3x3 rotation matrix.

to_xyzw_list(quaternion)

Converts to a list in XYZW order (for ROS/external system compatibility).

w(quaternion)

Returns the W (scalar) component.

x(quaternion)

Returns the X component.

y(quaternion)

Returns the Y component.

z(quaternion)

Returns the Z component.

## Types

# t()

    @type t() :: %BB.Math.Quaternion{tensor: Nx.Tensor.t()}

## Functions

# angular_distance(quaternion1, quaternion2)

    @spec angular_distance(t(), t()) :: float()

Computes the angular distance between two quaternions in radians.

Returns a value between 0 and pi.

## Examples

    iex> q1 = BB.Math.Quaternion.identity()
    iex> q2 = BB.Math.Quaternion.from_axis_angle(BB.Math.Vec3.unit_z(), :math.pi() / 2)
    iex> Float.round(BB.Math.Quaternion.angular_distance(q1, q2), 6)
    1.570796

# conjugate(quaternion)

    @spec conjugate(t()) :: t()

Returns the conjugate of a quaternion.

For unit quaternions, the conjugate equals the inverse.

## Examples

    iex> q = BB.Math.Quaternion.from_axis_angle(BB.Math.Vec3.unit_z(), :math.pi() / 2)
    iex> qc = BB.Math.Quaternion.conjugate(q)
    iex> Float.round(BB.Math.Quaternion.z(qc), 6)
    -0.707107

# from_axis_angle(vec3, angle)

    @spec from_axis_angle(BB.Math.Vec3.t(), number()) :: t()

Creates a quaternion from an axis-angle representation.

The axis should be a `BB.Math.Vec3` unit vector (it will be normalised if not). The angle is in radians.

## Examples

    iex> q = BB.Math.Quaternion.from_axis_angle(BB.Math.Vec3.unit_z(), :math.pi() / 2)
    iex> Float.round(BB.Math.Quaternion.w(q), 6)
    0.707107

# from_euler(roll, pitch, yaw, order \\ :xyz)

    @spec from_euler(number(), number(), number(), atom()) :: t()

Creates a quaternion from Euler angles (roll, pitch, yaw).

Angles are in radians. Default order is `:xyz` (roll around X, pitch around Y, yaw around Z).

Supported orders: `:xyz`, `:zyx`

## Examples

    iex> q = BB.Math.Quaternion.from_euler(0, 0, :math.pi() / 2, :xyz)
    iex> Float.round(BB.Math.Quaternion.z(q), 6)
    0.707107

# from_list(list)

    @spec from_list([number()]) :: t()

Creates from a list in WXYZ order.

## Examples

    iex> q = BB.Math.Quaternion.from_list([1.0, 0.0, 0.0, 0.0])
    iex> BB.Math.Quaternion.w(q)
    1.0

# from_rotation_matrix(matrix)

    @spec from_rotation_matrix(Nx.Tensor.t()) :: t()

Creates a quaternion from a 3x3 rotation matrix.

Uses the Shepperd method for numerical stability.

## Examples

    iex> m = Nx.tensor([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
    iex> q = BB.Math.Quaternion.from_rotation_matrix(m)
    iex> BB.Math.Quaternion.w(q)
    1.0

# from_tensor(tensor)

    @spec from_tensor(Nx.Tensor.t()) :: t()

Creates a quaternion from an existing `{4}` tensor.

The tensor should be in WXYZ order. It will be normalised.

# from_two_vectors(vec31, vec32)

    @spec from_two_vectors(BB.Math.Vec3.t(), BB.Math.Vec3.t()) :: t()

Creates a quaternion representing the shortest rotation from one vector to another.

Both vectors should be unit vectors (they will be normalised if not). Returns the quaternion that rotates `from` to align with `to`.

Handles edge cases:

- Parallel vectors (from ≈ to): returns identity quaternion
- Anti-parallel vectors (from ≈ -to): returns 180° rotation around a perpendicular axis

## Examples

    iex> q = BB.Math.Quaternion.from_two_vectors(BB.Math.Vec3.unit_x(), BB.Math.Vec3.unit_y())
    iex> rotated = BB.Math.Quaternion.rotate_vector(q, BB.Math.Vec3.unit_x())
    iex> {Float.round(BB.Math.Vec3.x(rotated), 6), Float.round(BB.Math.Vec3.y(rotated), 6)}
    {0.0, 1.0}

    iex> q = BB.Math.Quaternion.from_two_vectors(BB.Math.Vec3.unit_z(), BB.Math.Vec3.unit_z())
    iex> BB.Math.Quaternion.w(q)
    1.0

# from_xyzw_list(list)

    @spec from_xyzw_list([number()]) :: t()

Creates from a list in XYZW order (for ROS/external system compatibility).

## Examples

    iex> q = BB.Math.Quaternion.from_xyzw_list([0.0, 0.0, 0.0, 1.0])
    iex> BB.Math.Quaternion.w(q)
    1.0

# identity()

    @spec identity() :: t()

Returns the identity quaternion (no rotation).

## Examples

    iex> q = BB.Math.Quaternion.identity()
    iex> {BB.Math.Quaternion.w(q), BB.Math.Quaternion.x(q), BB.Math.Quaternion.y(q), BB.Math.Quaternion.z(q)}
    {1.0, 0.0, 0.0, 0.0}

# identity_tensor()

    @spec identity_tensor() :: Nx.Tensor.t()

Returns an identity quaternion as a raw tensor (for batch operations).

# inverse(q)

    @spec inverse(t()) :: t()

Returns the inverse of a quaternion.

For unit quaternions, this equals the conjugate.

## Examples

    iex> q = BB.Math.Quaternion.from_axis_angle(BB.Math.Vec3.unit_z(), :math.pi() / 2)
    iex> qi = BB.Math.Quaternion.inverse(q)
    iex> qr = BB.Math.Quaternion.multiply(q, qi)
    iex> Float.round(BB.Math.Quaternion.w(qr), 6)
    1.0

# multiply(quaternion1, quaternion2)

    @spec multiply(t(), t()) :: t()

Multiplies two quaternions (Hamilton product).

This composes the rotations: `multiply(q1, q2)` applies q2 first, then q1.

## Examples

    iex> q1 = BB.Math.Quaternion.from_axis_angle(BB.Math.Vec3.unit_z(), :math.pi() / 2)
    iex> q2 = BB.Math.Quaternion.from_axis_angle(BB.Math.Vec3.unit_z(), :math.pi() / 2)
    iex> q3 = BB.Math.Quaternion.multiply(q1, q2)
    iex> {_axis, angle} = BB.Math.Quaternion.to_axis_angle(q3)
    iex> Float.round(angle, 6)
    3.141593

# new(w, x, y, z)

    @spec new(number(), number(), number(), number()) :: t()

Creates a new quaternion from w, x, y, z components.

The quaternion is automatically normalised.

## Examples

    iex> q = BB.Math.Quaternion.new(1, 0, 0, 0)
    iex> BB.Math.Quaternion.w(q)
    1.0

# normalise(quaternion)

    @spec normalise(t()) :: t()

Normalises a quaternion to unit length.

## Examples

    iex> q = %BB.Math.Quaternion{tensor: Nx.tensor([2.0, 0.0, 0.0, 0.0])}
    iex> qn = BB.Math.Quaternion.normalise(q)
    iex> BB.Math.Quaternion.w(qn)
    1.0

# rotate_vector(quaternion, vec3)

    @spec rotate_vector(t(), BB.Math.Vec3.t()) :: BB.Math.Vec3.t()

Rotates a 3D vector by a quaternion.

## Examples

    iex> q = BB.Math.Quaternion.from_axis_angle(BB.Math.Vec3.unit_z(), :math.pi() / 2)
    iex> v = BB.Math.Vec3.unit_x()
    iex> rotated = BB.Math.Quaternion.rotate_vector(q, v)
    iex> {Float.round(BB.Math.Vec3.x(rotated), 6), Float.round(BB.Math.Vec3.y(rotated), 6)}
    {0.0, 1.0}

# slerp(quaternion1, quaternion2, t)

    @spec slerp(t(), t(), number()) :: t()

Spherical linear interpolation between two quaternions.

`t` should be between 0.0 and 1.0.

## Examples

    iex> q1 = BB.Math.Quaternion.identity()
    iex> q2 = BB.Math.Quaternion.from_axis_angle(BB.Math.Vec3.unit_z(), :math.pi())
    iex> q_mid = BB.Math.Quaternion.slerp(q1, q2, 0.5)
    iex> {_axis, angle} = BB.Math.Quaternion.to_axis_angle(q_mid)
    iex> Float.round(angle, 6)
    1.570796

# tensor(quaternion)

    @spec tensor(t()) :: Nx.Tensor.t()

Returns the underlying `{4}` tensor.

# to_axis_angle(quaternion)

    @spec to_axis_angle(t()) :: {BB.Math.Vec3.t(), float()}

Converts a quaternion to axis-angle representation.

Returns `{axis, angle}` where axis is a `BB.Math.Vec3` unit vector and angle is in radians (0 to pi).

## Examples

    iex> q = BB.Math.Quaternion.from_axis_angle(BB.Math.Vec3.unit_z(), :math.pi() / 2)
    iex> {axis, angle} = BB.Math.Quaternion.to_axis_angle(q)
    iex> Float.round(angle, 6)
    1.570796
    iex> Float.round(BB.Math.Vec3.z(axis), 1)
    1.0

# to_euler(q, order \\ :xyz)

    @spec to_euler(t(), atom()) :: {float(), float(), float()}

Converts a quaternion to Euler angles (roll, pitch, yaw).

Returns `{roll, pitch, yaw}` in radians. Default order is `:xyz`.

Note: Euler angles can have gimbal lock issues near pitch = ±90°.

## Examples

    iex> q = BB.Math.Quaternion.from_euler(0.1, 0.2, 0.3, :xyz)
    iex> {roll, pitch, yaw} = BB.Math.Quaternion.to_euler(q, :xyz)
    iex> Float.round(roll, 6)
    0.1

# to_list(quaternion)

    @spec to_list(t()) :: [float()]

Converts to a list in WXYZ order.

## Examples

    iex> q = BB.Math.Quaternion.identity()
    iex> BB.Math.Quaternion.to_list(q)
    [1.0, 0.0, 0.0, 0.0]

# to_rotation_matrix(quaternion)

    @spec to_rotation_matrix(t()) :: Nx.Tensor.t()

Converts a quaternion to a 3x3 rotation matrix.

## Examples

    iex> q = BB.Math.Quaternion.identity()
    iex> m = BB.Math.Quaternion.to_rotation_matrix(q)
    iex> Nx.to_number(m[0][0])
    1.0

# to_xyzw_list(quaternion)

    @spec to_xyzw_list(t()) :: [float()]

Converts to a list in XYZW order (for ROS/external system compatibility).

## Examples

    iex> q = BB.Math.Quaternion.identity()
    iex> BB.Math.Quaternion.to_xyzw_list(q)
    [0.0, 0.0, 0.0, 1.0]

# w(quaternion)

    @spec w(t()) :: float()

Returns the W (scalar) component.

# x(quaternion)

    @spec x(t()) :: float()

Returns the X component.

# y(quaternion)

    @spec y(t()) :: float()

Returns the Y component.

# z(quaternion)

    @spec z(t()) :: float()

Returns the Z component.