Skip to content

Quaternion

SUMMARY

A unit quaternion representing a rotation in 3D space.

python
from telekinesis import datatypes
quaternion = datatypes.Quaternion([1.0, 0.0, 0.0, 0.0])
API Reference
Complete API documentation for Quaternion, including parameters, attributes, and methods.
View Reference →

Parameters

ParameterTypeDefaultDescription
datanp.ndarray | list | tupleRequiredUnit quaternion [qw, qx, qy, qz] with shape (4,), using scalar-first ordering.

Raises

ExceptionCondition
TypeErrordata can't be converted to float32 (e.g. non-numeric elements)
ValueErrordata is not rank-1, or its shape isn't (4,)
ValueErrordata contains a non-finite value (NaN/Inf)
ValueErrordata's norm is non-finite, or is the zero quaternion (norm 0.0)
ValueErrordata's norm deviates from 1.0 by more than quat_norm_atol (1e-3)

Attributes

AttributeTypeDescription
datanp.ndarrayDefensive copy of the underlying (4,) float32 array, scalar-first [qw, qx, qy, qz]. Assigning a new value re-validates it (shape, finiteness, unit norm) the same way as construction.
shapetuple[int, ...]Always (4,).
ndimintAlways 1.
dtypenp.dtypeAlways float32.
sizeintAlways 4.
quat_norm_atolfloatClass-level, 1e-3 — max allowed abs(norm - 1).

Methods

MethodTypeDescription
Quaternion.coerce(value)QuaternionConverts array-like data into a Quaternion, running the same checks as the constructor, including the unit-norm check. If value is already a Quaternion, it is returned unchanged.
to_numpy(copy=True)np.ndarrayReturns the quaternion as a plain array. With the default copy=True you get an independent copy; pass copy=False to get a direct reference to the internal array instead, so mutating it also mutates the Quaternion.
copy()QuaternionReturns a new, independent Quaternion with the same data.

Operators

OperationBehavior
q == otherTrue only if other is also a Quaternion with element-equal data. False for anything else, including a Vector4D with the same values.
len(q)Always 4.
np.asarray(q)Returns a copy of data as an np.ndarray; NumPy functions accept a Quaternion directly.

Visualization

python
import rerun as rr

# Your code block
# ....

rr.init("quaternion_example", spawn=True)
datatypes.visualize(quaternion, entity_path="/quaternion", label="Quaternion")

Example

python
"""Demonstrates the Telekinesis Quaternion datatype."""

import time

import numpy as np
import rerun as rr
from loguru import logger
from scipy.spatial.transform import Rotation

from telekinesis import datatypes


def quaternion_example():
    """Demonstrate creation, inspection, operations, visualization, and serialization."""

    # ======================= Create ============================================
    quaternion = datatypes.Quaternion([0.4619398, 0.1913417, 0.4619398, 0.7325378])
    logger.info(f"Created Quaternion: {quaternion}")

    # ======================= Inspect ===========================================
    logger.info(f"data={quaternion.data}")
    logger.info(f"shape={quaternion.shape}")
    logger.info(f"ndim={quaternion.ndim}")
    logger.info(f"dtype={quaternion.dtype}")
    logger.info(f"size={quaternion.size}")
    logger.info(f"quat_norm_atol={quaternion.quat_norm_atol}")

    # ======================= Operations =========================================
    quaternion.data = [0.0, 0.0, 0.7071068, 0.7071068]
    logger.info(f"Updated Quaternion: {quaternion}")

    quaternion_copy = quaternion.copy()
    logger.info(f"Copied Quaternion: {quaternion_copy}")

    quaternion_numpy = quaternion.to_numpy(copy=True)
    logger.info(f"NumPy Quaternion: {quaternion_numpy}")

    numpy_array = np.asarray(quaternion)
    logger.info(f"NumPy array: {numpy_array}")

    norm = np.linalg.norm(quaternion)
    logger.info(f"Norm (np.linalg.norm): {norm}")

    # Quaternion.data is scalar-first [qw, qx, qy, qz]; scipy expects scalar-last
    # [qx, qy, qz, qw], so reorder before handing it to Rotation.from_quat.
    qw, qx, qy, qz = quaternion.data
    rotation_matrix = Rotation.from_quat([qx, qy, qz, qw]).as_matrix()
    logger.info(f"Equivalent rotation matrix (scipy Rotation):\n{rotation_matrix}")

    # ======================= Visualize =========================================
    rr.init("quaternion_example", spawn=True)
    datatypes.visualize(quaternion, entity_path="/quaternion", label="Updated Quaternion")

    # ======================= Serialize / Deserialize ===========================
    start = time.perf_counter()
    serialized = datatypes.serialize(quaternion)
    serialization_ms = (time.perf_counter() - start) * 1000

    start = time.perf_counter()
    deserialized = datatypes.deserialize(serialized)["param_0"]
    deserialization_ms = (time.perf_counter() - start) * 1000

    logger.info(f"Deserialized Quaternion: {deserialized}")
    logger.info(f"Round-trip successful: {quaternion == deserialized}")
    logger.info(f"Serialization time: {serialization_ms:.3f} ms")
    logger.info(f"Deserialization time: {deserialization_ms:.3f} ms")


if __name__ == "__main__":
    quaternion_example()