Poses3D
SUMMARY
A batch of positions and orientations in 3D space.
python
from telekinesis import datatypes
poses = datatypes.Poses3D([[1.0, 2.0, 3.0, 0.0, 0.0, 90.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]])Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
data | np.ndarray | list | tuple | Required | 3D poses with shape (N, 6), with one [x, y, z, roll, pitch, yaw] row per pose. Rotation uses Euler XYZ angles in degrees. |
Raises
| Exception | Condition |
|---|---|
TypeError | data can't be converted to float32 (e.g. non-numeric elements) |
ValueError | data is not rank-2, or its last axis isn't length 6 |
ValueError | data contains a non-finite value (NaN/Inf) |
Attributes
| Attribute | Type | Description |
|---|---|---|
data | np.ndarray | Defensive copy of the underlying (N, 6) float32 array. Assigning a new value re-validates it the same way as construction. |
shape | tuple[int, ...] | (N, 6), where N is the batch size. |
ndim | int | Always 2. |
dtype | np.dtype | Always float32. |
size | int | N * 6. |
positions | np.ndarray | Positions, shape (N, 3) — a copy of data[:, 0:3]. |
orientations | np.ndarray | Euler XYZ orientations in degrees, shape (N, 3) — a copy of data[:, 3:6]. |
Methods
| Method | Type | Description |
|---|---|---|
Poses3D.coerce(value) | Poses3D | Converts array-like data into a Poses3D. Accepts an (N, 6) array-like, one [x, y, z, roll, pitch, yaw] row per pose, checked the same way as the constructor. If value is already a Poses3D, it is returned unchanged. |
Poses3D.from_quat(poses) | Poses3D | Builds a Poses3D from quaternion-encoded poses (shape (N, 7)), each row [x, y, z, qw, qx, qy, qz] — position followed by a scalar-first quaternion — stored as the native degree-based Euler orientation. The input must be a 2D array with a 4-element quaternion per row. |
Poses3D.from_euler(poses, degrees=True) | Poses3D | Builds a Poses3D from Euler-XYZ-encoded poses (shape (N, 6)), each row [x, y, z, roll, pitch, yaw]. degrees selects whether the input rotations are given in degrees (default) or radians; either way they're stored as degrees. The input must be a 2D array with a 3-element rotation part per row. |
Poses3D.from_rotvec(poses) | Poses3D | Builds a Poses3D from rotation-vector-encoded poses (shape (N, 6)), each row [x, y, z, rx, ry, rz] — position followed by an axis-angle rotation vector. The input must be a 2D array with a 3-element rotation part per row. |
to_numpy(copy=True) | np.ndarray | Returns the poses' coordinates 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 Poses3D. |
copy() | Poses3D | Returns a new, independent Poses3D with the same data. |
Representations
| Representation | Method | Result |
|---|---|---|
| Quaternion | as_quat() | (N, 7) float32, each row [x, y, z, qw, qx, qy, qz] — that pose's position, followed by a scalar-first quaternion equivalent to its Euler XYZ orientation. |
| Euler XYZ | as_euler(degrees=True) | (N, 6) float32, each row [x, y, z, roll, pitch, yaw]. degrees=True (default, this batch's native representation) or degrees=False for radians. Always an independent copy. |
| Rotation vector | as_rotvec() | (N, 6) float32, each row [x, y, z, rx, ry, rz] — position, followed by a rotation vector (axis-angle, magnitude = angle in radians). |
Operators
| Operation | Behavior |
|---|---|
p == other | True only if other is also a Poses3D with element-equal data (same N, same values). False for anything else. |
len(p) | The batch size N (length of the first axis). |
poses[i] | Returns a Pose3D for an integer index (negative indices supported). Raises IndexError if out of range. |
poses[a:b] / poses[mask] | Returns a new Poses3D holding the matched rows, for a slice or a boolean np.ndarray mask. Any other index type raises TypeError. |
for p in poses | Iterates via __getitem__ (the old-style sequence protocol), yielding one Pose3D per row in order. |
np.asarray(p) / np.reshape(p, ...) | Returns a copy of data as an np.ndarray; NumPy functions accept a Poses3D directly. |
Visualization
python
import rerun as rr
# Your code block
# ....
rr.init("poses3d_example", spawn=True)
datatypes.visualize(poses, entity_path="/poses", label="Poses3D")Example
python
"""Demonstrates the Telekinesis Poses3D datatype."""
import time
import numpy as np
import rerun as rr
from loguru import logger
from telekinesis import datatypes
def poses3d_example():
"""Demonstrate creation, inspection, operations, visualization, and serialization."""
# ======================= Create ============================================
poses_data = [[0.5, 0.2, 0.5, 0.0, 60.0, 90.0], [0.1, 0.2, 0.3, 0.0, 0.0, 90.0]]
poses3d = datatypes.Poses3D(poses_data)
logger.info(f"Created Poses3D: {poses3d}")
poses3d_from_quat = datatypes.Poses3D.from_quat(
[
[0.5, 0.2, 0.8, 0.0, 0.0, 0.3826834, 0.9238795],
[0.1, 0.2, 0.3, 0.0, 0.0, 0.0, 1.0],
]
)
logger.info(f"Poses3D created from quaternion: {poses3d_from_quat}")
poses3d_from_euler = datatypes.Poses3D.from_euler(
[
[0.5, 0.2, 0.8, np.radians(30), np.radians(45), np.radians(60)],
[0.1, 0.2, 0.3, 0.0, 0.0, 0.0],
],
degrees=False,
)
logger.info(f"Poses3D created from radians: {poses3d_from_euler}")
poses3d_from_rotvec = datatypes.Poses3D.from_rotvec(
[
[0.5, 0.2, 0.8, 0.0, 0.0, np.pi / 2],
[0.1, 0.2, 0.3, 0.0, 0.0, 0.0],
]
)
logger.info(f"Poses3D created from rotation vector: {poses3d_from_rotvec}")
# ======================= Inspect ===========================================
logger.info(f"data={poses3d.data}")
logger.info(f"shape={poses3d.shape}")
logger.info(f"ndim={poses3d.ndim}")
logger.info(f"dtype={poses3d.dtype}")
logger.info(f"size={poses3d.size}")
logger.info(f"positions={poses3d.positions}")
logger.info(f"orientations={poses3d.orientations}")
# ======================= Operations =========================================
poses3d.data = [[0.1, 0.2, 0.3, 0.0, 0.0, 90.0], [0.4, 0.5, 0.6, 0.0, 0.0, 45.0]]
logger.info(f"Updated Poses3D: {poses3d}")
poses3d_copy = poses3d.copy()
logger.info(f"Copied Poses3D: {poses3d_copy}")
poses3d_numpy = poses3d.to_numpy(copy=True)
logger.info(f"NumPy Poses3D: {poses3d_numpy}")
poses3d_quat = poses3d.as_quat()
logger.info(f"Poses3D as quaternion: {poses3d_quat}")
poses3d_euler_deg = poses3d.as_euler(degrees=True)
logger.info(f"Poses3D as Euler degrees: {poses3d_euler_deg}")
poses3d_euler_rad = poses3d.as_euler(degrees=False)
logger.info(f"Poses3D as Euler radians: {poses3d_euler_rad}")
poses3d_rotvec = poses3d.as_rotvec()
logger.info(f"Poses3D as rotation vector: {poses3d_rotvec}")
first_pose3d = poses3d[0]
logger.info(f"First Pose3D via indexing: {first_pose3d}")
poses3d_subset = poses3d[0:1]
logger.info(f"Poses3D subset via slicing: {poses3d_subset}")
reshaped = np.reshape(poses3d, (2, 6))
logger.info(f"Poses3D with np.reshape: {reshaped}")
# ======================= Visualize =========================================
rr.init("poses3d_example", spawn=True)
datatypes.visualize(poses3d, entity_path="/poses3d", label=["Poses3D 0", "Poses3D 1"])
# ======================= Serialize / Deserialize ===========================
start = time.perf_counter()
serialized = datatypes.serialize(poses3d)
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 Poses3D: {deserialized}")
logger.info(f"Round-trip successful: {poses3d == deserialized}")
logger.info(f"Serialization time: {serialization_ms:.3f} ms")
logger.info(f"Deserialization time: {deserialization_ms:.3f} ms")
if __name__ == "__main__":
poses3d_example()
