Skip to content

Circle

Represents one circle: a center and a radius.

Parameters

FieldTypeDescription
centerlist[float] | np.ndarrayCircle center, converted to a contiguous float32 array of shape (2,): [x, y].
radiusfloatCircle radius, must be >= 0.

Raises

ExceptionCondition
ValueErrorcenter's shape (after conversion) isn't (2,), or radius < 0

Conversion of center to float32 (np.asarray(center, dtype=np.float32)) isn't wrapped in a try/except, so a value NumPy can't cast (e.g. a non-numeric string) raises whatever NumPy itself produces instead of a uniform Circle-specific error — empirically, Circle(center=["a", "b"], radius=1.0) raises ValueError: could not convert string to float: 'a', but other inputs could just as easily surface a TypeError.

Attributes

AttributeTypeDescription
centernp.ndarrayDefensive copy of the circle center, shape (2,), float32.
radiusfloatThe circle radius.

Methods

MethodDescription
translate(offset)Returns a new Circle with center shifted by offset (array-like [dx, dy]). radius unchanged.
scale(factor)Returns a new Circle with radius multiplied by factor. center unchanged.
Circle.coerce(value)Returns value unchanged if it's already a Circle; builds one from a dict with keys center and radius otherwise. Raises TypeError for anything else.

Operators

OperationBehavior
circle == otherTrue only if other is a Circle with an equal center (elementwise) and an equal radius. NotImplemented (so False) for any other type.
hash(circle)Not supported, despite being immutable after construction (__hash__ = None).
repr(circle)Circle(center=[50. 60.], radius=10.0) — verified empirically.

Visualization

datatypes.visualize(circle, entity_path=..., label=...) logs the circle as a rerun ellipse with equal half-sizes on both axes (rr.Ellipses2D(centers=circle.center.reshape(1, 2), half_sizes=[[radius, radius]])), which renders as a true circle rather than a bounding box. Pass label as a single str to render a floating text label at the circle's center.

Example

python
"""Demonstrates the Telekinesis Circle datatype."""

import time

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

from telekinesis import datatypes

def circle_example():
    """Demonstrate creation, access, translation and scaling of the immutable Circle, visualization, and serialization."""

    # ======================= Create ============================================
    circle = datatypes.Circle(center=[50.0, 60.0], radius=10.0)
    logger.info(f"Original Circle: {circle}")

    # ======================= Inspect ===========================================
    logger.info(f"center={circle.center}, radius={circle.radius}")

    # ======================= Translate / Scale =================================
    translated = circle.translate([5.0, 5.0])
    scaled = translated.scale(1.5)
    logger.info(f"Translated Circle: {translated}")
    logger.info(f"Scaled Circle: {scaled}")

    # ======================= Visualize =========================================
    rr.init("circle_example", spawn=True)
    datatypes.visualize(circle, entity_path="/Circle", label="My Circle")
    datatypes.visualize(scaled, entity_path="/Circle/updated", label="Updated Circle")

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


if __name__ == "__main__":
    circle_example()