Point2D
Represents a single 2D point.
Parameters
| Field | Type | Description |
|---|---|---|
data | np.ndarray | list | tuple | Array-like input, converted to a contiguous float32 array of shape (2,): [x, y]. |
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 2, or it contains a non-finite value (NaN/Inf) |
Attributes
| Attribute | Type | Description |
|---|---|---|
data | np.ndarray | The wrapped point, shape (2,). Reading it returns a copy, so mutating the result doesn't affect the Point2D; assigning a new value re-validates it the same way as construction. |
shape | tuple[int, ...] | Always (2,). |
ndim | int | Always 1. |
dtype | np.dtype | Always float32. |
size | int | Always 2. |
shape_spec | ClassVar[tuple[int, ...]] | Class-level shape contract, (2,), inherited from Vector2D. Same for every Point2D instance. |
Methods
| Method | Description |
|---|---|
to_numpy(copy=True) | Returns the point as np.ndarray, shape (2,). Pass copy=False to get a reference to the internal array instead — faster, but mutating it mutates the Point2D too. |
copy() | Returns a new Point2D with an independent copy of the data. |
Point2D.coerce(value) | Returns value unchanged if it's already a Point2D; wraps a np.ndarray/list/tuple into one otherwise. Raises TypeError for anything else — including a plain Vector2D, since isinstance against Point2D doesn't match its own parent class. |
Operators
| Operation | Behavior |
|---|---|
point == other | True only if other is also exactly a Point2D (not a Vector2D or any other type, even with identical coordinates) with equal values (NaN counts as equal to NaN). False for anything else. |
len(point) | Always 2 — the length of axis 0 of the underlying (2,) array, not a "number of points" count. |
np.asarray(point) | Works directly — NumPy functions accept a Point2D 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 Point2D itself (no __add__/__array_ufunc__). Verified empirically: with a NumPy array operand, NumPy coerces the Point2D via __array__ and performs plain elementwise arithmetic — the result is a plain np.ndarray, not a Point2D. |
hash(point) | Not supported — raises TypeError: unhashable type: 'Point2D'. |
Visualization
datatypes.visualize(point, entity_path=..., label=...) logs the point as a single rerun 2D point (rr.Points2D(positions=point.data.reshape(1, 2))) — the same handler also backs Position2D. Pass label as a single str to additionally render a floating text label at the point's position.
Example
python
"""Demonstrates the Telekinesis Point2D datatype."""
import time
import numpy as np
from loguru import logger
import rerun as rr
from telekinesis import datatypes
def point2d_example():
"""Demonstrate creation, access, visualization, update, NumPy arithmetic, and serialization."""
# ======================= Create ============================================
point = [1.0, 2.0]
point2d = datatypes.Point2D(point)
logger.info(f"Original Point2D: {point2d}")
# ======================= Inspect ===========================================
data = point2d.data
shape = point2d.shape
size = point2d.size
dtype = point2d.dtype
ndim = point2d.ndim
numpy_point2d = point2d.to_numpy()
point2d_copy = point2d.copy()
logger.info(f"shape={shape}, size={size}, ndim={ndim}, dtype={dtype}")
logger.info(f"Underlying data: {data}")
logger.info(f"NumPy array: {numpy_point2d}")
logger.info(f"Copy: {point2d_copy}")
# ======================= Visualize =========================================
rr.init("point2d_example", spawn=True)
datatypes.visualize(point2d, entity_path="/Point2D", label="My Point2D")
# ======================= Update ============================================
new_data = [3.0, 4.0]
point2d.data = new_data
logger.info(f"Updated Point2D: {point2d}")
datatypes.visualize(point2d, entity_path="/Point2D/updated", label="Updated Point2D")
# ======================= Arithmetic ========================================
point_sum = point2d + np.array([1.0, 1.0])
point_diff = point2d - np.array([1.0, 1.0])
point_prod = point2d * np.array(2.0)
point_quot = point2d / 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(point2d)
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 Point2D: {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__":
point2d_example()
