Point3D
Represents a single 3D point.
Parameters
| Field | Type | Description |
|---|---|---|
data | np.ndarray | list | tuple | Array-like input, converted to a contiguous float32 array of shape (3,): [x, y, z]. |
Raises
| Exception | Condition |
|---|---|
TypeError | data can't be converted to a float32 array (e.g. ragged nested lists, non-numeric elements) |
ValueError | The converted array isn't 1-D, its length isn't 3, or it contains a non-finite value (NaN/Inf) |
Attributes
| Attribute | Type | Description |
|---|---|---|
data | np.ndarray | The wrapped point, shape (3,). Reading it returns a copy, so mutating the result doesn't affect the Point3D; assigning a new value re-validates it the same way as construction. |
shape | tuple[int, ...] | Always (3,). |
ndim | int | Always 1. |
dtype | np.dtype | Always float32. |
size | int | Always 3. |
shape_spec | ClassVar[tuple[int, ...]] | Class-level shape contract, (3,), inherited from Vector3D. Same for every Point3D instance. |
Methods
| Method | Description |
|---|---|
to_numpy(copy=True) | Returns the point as np.ndarray, shape (3,). Pass copy=False to get a reference to the internal array instead — faster, but mutating it mutates the Point3D too. |
copy() | Returns a new Point3D with an independent copy of the data. |
Point3D.coerce(value) | Returns value unchanged if it's already a Point3D; wraps a np.ndarray/list/tuple into one otherwise. Raises TypeError for anything else — including a plain Vector3D, since isinstance against Point3D doesn't match its own parent class. |
Operators
| Operation | Behavior |
|---|---|
point == other | True only if other is also exactly a Point3D (not a Vector3D or any other type, even with identical coordinates) with equal values (NaN counts as equal to NaN). False for anything else. |
len(point) | Always 3 — the length of axis 0 of the underlying (3,) array, not a "number of points" count. |
np.asarray(point) | Works directly — NumPy functions accept a Point3D in place of an np.ndarray. Always returns a copy; use to_numpy(copy=False) for a zero-copy view. |
point + arr, point - arr, point * arr, point / arr | Not implemented on Point3D itself (no __add__/__array_ufunc__). As verified for Point2D: with a NumPy array operand, NumPy coerces the Point3D via __array__ and performs plain elementwise arithmetic — the result is a plain np.ndarray, not a Point3D. |
hash(point) | Not supported — raises TypeError: unhashable type: 'Point3D'. |
Visualization
datatypes.visualize(point, entity_path=..., label=...) logs the point as a single rerun 3D point (rr.Points3D(positions=point.data.reshape(1, 3))) — the same handler also backs Position3D. Pass label as a single str to additionally render a floating text label at the point's position.
Example
python
"""Demonstrates the Telekinesis Point3D datatype."""
import time
import numpy as np
from loguru import logger
import rerun as rr
from telekinesis import datatypes
def point3d_example():
"""Demonstrate creation, access, visualization, update, NumPy arithmetic, and serialization."""
# ======================= Create ============================================
point = [1.0, 2.0, 3.0]
point3d = datatypes.Point3D(point)
logger.info(f"Original Point3D: {point3d}")
# ======================= Inspect ===========================================
data = point3d.data
shape = point3d.shape
size = point3d.size
dtype = point3d.dtype
ndim = point3d.ndim
numpy_point3d = point3d.to_numpy()
point3d_copy = point3d.copy()
logger.info(f"shape={shape}, size={size}, ndim={ndim}, dtype={dtype}")
logger.info(f"Underlying data: {data}")
logger.info(f"NumPy array: {numpy_point3d}")
logger.info(f"Copy: {point3d_copy}")
# ======================= Visualize =========================================
rr.init("point3d_example", spawn=True)
datatypes.visualize(point3d, entity_path="/Point3D", label="My Point3D")
# ======================= Update ============================================
new_data = [4.0, 5.0, 6.0]
point3d.data = new_data
logger.info(f"Updated Point3D: {point3d}")
datatypes.visualize(point3d, entity_path="/Point3D/updated", label="Updated Point3D")
# ======================= Arithmetic ========================================
point_sum = point3d + np.array([1.0, 1.0, 1.0])
point_diff = point3d - np.array([1.0, 1.0, 1.0])
point_prod = point3d * np.array(2.0)
point_quot = point3d / np.array(2.0)
logger.info(f"Sum: {point_sum}, Difference: {point_diff}")
logger.info(f"Product: {point_prod}, Quotient: {point_quot}")
# ======================= Serialize / Deserialize ===========================
start = time.perf_counter()
serialized = datatypes.serialize(point3d)
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 Point3D: {deserialized}")
logger.info(f"Round-trip successful: {deserialized.data == new_data}")
logger.info(f"Serialization time: {serialization_ms:.3f} ms")
logger.info(f"Deserialization time: {deserialization_ms:.3f} ms")
if __name__ == "__main__":
point3d_example()
