Skip to content

Contour

Represents one contour: an ordered list of 2D polygon vertices.

Parameters

FieldTypeDescription
pointslist[list[int]] | np.ndarrayContour vertices, converted to a contiguous int64 array of shape (K, 2). K can be 0.

Raises

ExceptionCondition
ValueErrorpoints, after conversion to int64, isn't 2-D or its second axis isn't length 2

Conversion of points to int64 (np.asarray(points, dtype=np.int64)) isn't wrapped in a try/except; a value NumPy can't cast raises whatever error NumPy itself produces.

Attributes

AttributeTypeDescription
pointsnp.ndarrayDefensive copy of the contour vertices, shape (K, 2), int64.

Methods

MethodDescription
Contour.coerce(value)Returns value unchanged if it's already a Contour; wraps a np.ndarray/list into one otherwise. Raises TypeError for anything else.

Operators

OperationBehavior
contour == otherTrue only if other is a Contour with an equal points array. NotImplemented (so False) for any other type.
len(contour)The vertex count, K.
hash(contour)Not supported, despite being immutable after construction (__hash__ = None).
repr(contour)Contour(num_points=3) — verified empirically.

Visualization

datatypes.visualize(contour, entity_path=...) logs the contour as a closed rerun 2D line strip (rr.LineStrips2D([strip])), where strip repeats the contour's first vertex at the end to close the polygon loop. Contour has no registered label handler — passing label= to visualize() for a Contour is silently ignored (no error, no label rendered).

Example

python
"""Demonstrates the Telekinesis Contour datatype."""

import time

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

from telekinesis import datatypes

def contour_example():
    """Demonstrate creation, inspection, visualization, NumPy-based shifting, and serialization."""

    # ======================= Create ============================================
    contour = datatypes.Contour(
        points=np.array([[118, 84], [134, 79], [150, 86], [139, 115]], dtype=np.int64),
    )
    logger.info(f"Original Contour: {contour}")

    # ======================= Inspect ===========================================
    points = contour.points
    num_points = len(contour)

    logger.info(f"Points: {points}")
    logger.info(f"Number of points: {num_points}")

    # ======================= Visualize =========================================
    rr.init("contour_example", spawn=True)
    datatypes.visualize(contour, entity_path="/Contour")

    # ======================= Shift =============================================
    shifted_points = points + np.array([10, 10], dtype=np.int64)
    shifted_contour = datatypes.Contour(points=shifted_points)
    logger.info(f"Shifted Contour: {shifted_contour}")
    datatypes.visualize(shifted_contour, entity_path="/Contour/shifted")

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


if __name__ == "__main__":
    contour_example()