Skip to content

Circles

SUMMARY

A batch of circles in 2D space.

python
from telekinesis import datatypes
circles = datatypes.Circles(centers=[[50.0, 60.0], [120.0, 80.0]], radii=[10.0, 15.5])
API Reference
Complete API documentation for Circles, including parameters, attributes, and methods.
View Reference →

Parameters

ParameterTypeDefaultDescription
centerslist[list[float]] | np.ndarrayRequiredCircle centers with shape (N, 2), with one [x, y] row per circle.
radiilist[float] | np.ndarrayRequiredCircle radii, shape (N,), each >= 0.

Raises

ExceptionCondition
TypeErrorcenters or radii can't be converted to a float32 array
ValueErrorcenters's shape (after conversion) isn't (N, 2), radii's shape isn't (N,) or its length doesn't match centers's N, any radius is negative, or centers/radii contain a non-finite value (NaN/Inf)

Attributes

AttributeTypeDescription
centersnp.ndarrayDefensive copy of the circle centers, shape (N, 2), float32.
radiinp.ndarrayDefensive copy of the circle radii, shape (N,), float32.

Methods

MethodTypeDescription
Circles.coerce(value)CirclesConverts a dict with centers and radii keys into a Circles. If value is already a Circles, it is returned unchanged.

Operators

OperationBehavior
circles == otherTrue only if other is a Circles with equal centers and radii arrays. NotImplemented (so False) for any other type.
len(circles)The number of circles, N.
circles[i]An int returns a single Circle for that row (supports negative indices). A slice or a boolean np.ndarray mask returns a new Circles sub-batch. Raises IndexError for an out-of-range int, ValueError for a wrongly-sized boolean mask, TypeError for any other index type.
repr(circles)Circles(num_circles=3, radius_range=[1.0, 3.0]), or Circles(num_circles=0) when empty — verified empirically.

Visualization

python
import rerun as rr

# Your code block
# ....

rr.init("circles_example", spawn=True)
datatypes.visualize(circles, entity_path="/circles", label="Circles")

Example

python
"""Demonstrates the Telekinesis Circles datatype."""

import time

import numpy as np
import rerun as rr
from loguru import logger

from telekinesis import datatypes

def circles_example():
    """Demonstrate creation, inspection, operations, visualization, and serialization."""

    # ======================= Create ============================================
    circles = datatypes.Circles(
        centers=np.array([[50.0, 60.0], [120.0, 80.0], [200.0, 150.0]], dtype=np.float32),
        radii=np.array([10.0, 15.5, 7.25], dtype=np.float32),
    )
    logger.info(f"Original Circles: {circles}")

    circles_from_dict = datatypes.Circles.coerce(
        {"centers": [[0.0, 0.0], [10.0, 10.0]], "radii": [1.0, 2.0]}
    )
    logger.info(f"Circles coerced from dict: {circles_from_dict}")

    # ======================= Inspect ===========================================
    logger.info(f"centers={circles.centers}")
    logger.info(f"radii={circles.radii}")

    # ======================= Operations =========================================
    logger.info(f"Number of circles: {len(circles)}")

    first_circle = circles[0]
    sub_batch = circles[1:]
    logger.info(f"First circle: {first_circle}")
    logger.info(f"Sub-batch [1:]: {sub_batch}")

    # Circles is immutable; translate and scale by constructing a new instance.
    offsets = np.array([[5.0, 5.0], [10.0, 0.0], [-5.0, -5.0]], dtype=np.float32)
    translated_circles = datatypes.Circles(centers=circles.centers + offsets, radii=circles.radii)
    logger.info(f"Translated Circles: {translated_circles}")

    scaled_circles = datatypes.Circles(
        centers=translated_circles.centers, radii=translated_circles.radii * 1.5
    )
    logger.info(f"Scaled Circles: {scaled_circles}")

    # ======================= Visualize =========================================
    rr.init("circles_example", spawn=True)
    datatypes.visualize(
        circles,
        entity_path="/circles/original",
        label=["Original Circle 1", "Original Circle 2", "Original Circle 3"],
    )
    datatypes.visualize(
        scaled_circles,
        entity_path="/circles/scaled",
        label=["Scaled Circle 1", "Scaled Circle 2", "Scaled Circle 3"],
    )

    # ======================= Serialize / Deserialize ===========================
    start = time.perf_counter()
    serialized = datatypes.serialize(scaled_circles)
    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 Circles: {deserialized}")
    logger.info(f"Round-trip successful: {scaled_circles == deserialized}")
    logger.info(f"Serialization time: {serialization_ms:.3f} ms")
    logger.info(f"Deserialization time: {deserialization_ms:.3f} ms")


if __name__ == "__main__":
    circles_example()