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])Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
data | np.ndarray | list | tuple | Required | Unit quaternion [qw, qx, qy, qz] with shape (4,), using scalar-first ordering. |
Raises
| Exception | Condition |
|---|---|
TypeError | data can't be converted to float32 (e.g. non-numeric elements) |
ValueError | data is not rank-1, or its shape isn't (4,) |
ValueError | data contains a non-finite value (NaN/Inf) |
ValueError | data's norm is non-finite, or is the zero quaternion (norm 0.0) |
ValueError | data's norm deviates from 1.0 by more than quat_norm_atol (1e-3) |
Attributes
| Attribute | Type | Description |
|---|---|---|
data | np.ndarray | Defensive 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. |
shape | tuple[int, ...] | Always (4,). |
ndim | int | Always 1. |
dtype | np.dtype | Always float32. |
size | int | Always 4. |
quat_norm_atol | float | Class-level, 1e-3 — max allowed abs(norm - 1). |
Methods
| Method | Type | Description |
|---|---|---|
Quaternion.coerce(value) | Quaternion | Converts 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.ndarray | Returns 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() | Quaternion | Returns a new, independent Quaternion with the same data. |
Operators
| Operation | Behavior |
|---|---|
q == other | True 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()
