Twist3D
Represents a 3D twist: a linear velocity plus an angular velocity.
Parameters
| Field | Type | Description |
|---|---|---|
data | np.ndarray | list | tuple | Array-like input of shape (6,): [vx, vy, vz, wx, wy, wz], converted to a contiguous float32 array. |
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 (6,) |
ValueError | data contains a non-finite value (NaN/Inf) |
Attributes
| Attribute | Type | Description |
|---|---|---|
data | np.ndarray | Defensive copy of the underlying (6,) float32 array. Assigning a new value re-validates it the same way as construction. |
shape | tuple[int, ...] | Always (6,). |
ndim | int | Always 1. |
dtype | np.dtype | Always float32. |
size | int | Always 6. |
Methods
| Method | Description |
|---|---|
to_numpy(copy=True) | Returns the twist as np.ndarray. Pass copy=False for a reference to the internal array instead — faster, but mutating it mutates the Twist3D too. |
copy() | Returns a new Twist3D with an independent copy of the data. |
Twist3D.coerce(value) | Returns value unchanged if it's already a Twist3D; otherwise wraps an array-like into one. Raises TypeError for any other input. |
Operators
| Operation | Behavior |
|---|---|
t == other | True only if other is also a Twist3D with element-equal data. False for anything else. |
len(t) | Always 6. |
np.asarray(t) | Works directly via __array__. Always returns a copy; use to_numpy(copy=False) for a zero-copy view. |
hash(t) | Not supported — mutable via the data setter. |
Visualization
datatypes.visualize(twist, entity_path=...) logs a static reference frame pinned at the world origin (labeled "origin"), then integrates the linear velocity v and angular velocity ω via the Rodrigues rotation formula over 100 synthetic timesteps (step=0.05s each) on a "time" sequence timeline, logging a moving frame at each step so the viewer can play back the resulting motion. Passing label="..." attaches a floating text label at the static origin frame.
Example
python
"""Demonstrates the Telekinesis Twist3D datatype."""
import time
import numpy as np
from loguru import logger
import rerun as rr
from telekinesis import datatypes
def twist3d_example():
"""Demonstrate creation, access, visualization, update, NumPy interop, and serialization."""
# ======================= Create ============================================
values = np.array([0.1, 0.0, 0.0, 0.0, 0.0, 0.2], dtype=np.float32)
twist3d = datatypes.Twist3D(values)
logger.info(f"Input values: {values}")
logger.info(f"Created Twist3D: {twist3d}")
# ======================= Inspect ===========================================
data = twist3d.data
shape = twist3d.shape
size = twist3d.size
dtype = twist3d.dtype
ndim = twist3d.ndim
numpy_array = twist3d.to_numpy()
twist3d_copy = twist3d.copy()
logger.info(f"shape={shape}, size={size}, ndim={ndim}, dtype={dtype}")
logger.info(f"Twist3D data: {data}")
logger.info(f"NumPy array: {numpy_array}")
logger.info(f"Copied Twist3D: {twist3d_copy}")
# ======================= Visualize =========================================
rr.init("twist3d_example", spawn=True)
datatypes.visualize(twist3d, entity_path="/Twist3D/main", label="Original Twist3D")
# ======================= Update ============================================
twist3d.data = np.array([0.0, 0.3, 0.0, 0.1, 0.0, 0.0], dtype=np.float32)
logger.info(f"Updated Twist3D: {twist3d}")
datatypes.visualize(twist3d, entity_path="/Twist3D/updated", label="Updated Twist3D")
# ======================= NumPy Interop =====================================
linear = numpy_array[:3]
angular = numpy_array[3:]
linear_speed = np.linalg.norm(linear)
angular_speed = np.linalg.norm(angular)
logger.info(f"Linear velocity (vx, vy, vz): {linear}")
logger.info(f"Angular velocity (wx, wy, wz): {angular}")
logger.info(f"linear_speed={linear_speed}, angular_speed={angular_speed}")
# ======================= Serialize / Deserialize ===========================
start = time.perf_counter()
serialized = datatypes.serialize(twist3d)
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 Twist3D: {deserialized}")
logger.info(f"Round-trip successful: {deserialized == twist3d}")
logger.info(f"Serialization time: {serialization_ms:.3f} ms")
logger.info(f"Deserialization time: {deserialization_ms:.3f} ms")
if __name__ == "__main__":
twist3d_example()
