Skip to content

angle

angle #

Circular angular distance between two angles.

Measures distance between angles accounting for their circular nature. For example, 359° is close to 1°.

CircularAngleDistanceFunction #

Bases: BatchedDistanceFunction[float]

Shortest angular separation on a circle, normalized by sigma.

Degrees and radians differ only in sigma and period.

Source code in capturegraph-lib/capturegraph/scheduling/distance/angle.py
class CircularAngleDistanceFunction(BatchedDistanceFunction[float]):
    """Shortest angular separation on a circle, normalized by ``sigma``.

    Degrees and radians differ only in ``sigma`` and ``period``.
    """

    def __init__(self, sigma: float, period: float) -> None:
        """Normalize by ``sigma``, wrapping angles at ``period``."""
        self.sigma = sigma
        self.period = period

    def __call__(self, a: float, b: float) -> float:
        """Shortest angular separation between ``a`` and ``b``, normalized."""
        diff = abs(a - b) % self.period
        return min(diff, self.period - diff) / self.sigma

    def extract(self, items: cg.Array[Any]) -> np.ndarray:
        """Extract raw angle values as a single-column feature array."""
        return np.array(list(items), dtype=np.float64).reshape(-1, 1)

    def pairwise(self, features_a: np.ndarray, features_b: np.ndarray) -> np.ndarray:
        """Compute pairwise circular distances from extracted angle features."""
        gap = np.abs(features_a[:, 0][:, None] - features_b[:, 0][None, :])
        diff = gap % self.period
        return np.minimum(diff, self.period - diff) / self.sigma

__call__(a, b) #

Shortest angular separation between a and b, normalized.

Source code in capturegraph-lib/capturegraph/scheduling/distance/angle.py
def __call__(self, a: float, b: float) -> float:
    """Shortest angular separation between ``a`` and ``b``, normalized."""
    diff = abs(a - b) % self.period
    return min(diff, self.period - diff) / self.sigma

__init__(sigma, period) #

Normalize by sigma, wrapping angles at period.

Source code in capturegraph-lib/capturegraph/scheduling/distance/angle.py
def __init__(self, sigma: float, period: float) -> None:
    """Normalize by ``sigma``, wrapping angles at ``period``."""
    self.sigma = sigma
    self.period = period

extract(items) #

Extract raw angle values as a single-column feature array.

Source code in capturegraph-lib/capturegraph/scheduling/distance/angle.py
def extract(self, items: cg.Array[Any]) -> np.ndarray:
    """Extract raw angle values as a single-column feature array."""
    return np.array(list(items), dtype=np.float64).reshape(-1, 1)

pairwise(features_a, features_b) #

Compute pairwise circular distances from extracted angle features.

Source code in capturegraph-lib/capturegraph/scheduling/distance/angle.py
def pairwise(self, features_a: np.ndarray, features_b: np.ndarray) -> np.ndarray:
    """Compute pairwise circular distances from extracted angle features."""
    gap = np.abs(features_a[:, 0][:, None] - features_b[:, 0][None, :])
    diff = gap % self.period
    return np.minimum(diff, self.period - diff) / self.sigma

angle_degrees(sigma_deg=10.0, period=360.0) #

Create a circular angular distance function for degrees.

Measures the shortest angular distance between two angles on a circle. By default, assumes 360° period (full rotation).

Parameters:

Name Type Description Default
sigma_deg float

Normalization factor in degrees. Angles within sigma_deg apart have distance < 1.0. Default is 10°.

10.0
period float

The period of the angle in degrees. Default is 360° (full circle). Use 180° for angles that wrap at ±90° (like latitude).

360.0

Returns:

Type Description
CircularAngleDistanceFunction

A distance function (angle_a, angle_b) -> float with batch support.

Example
import capturegraph.scheduling as cgsh

# Azimuth angles (0-360°)
dist_fn = cgsh.distance.angle_degrees(sigma_deg=15.0)

# Use with combine
combined = cgsh.distance.combine(azimuth=cgsh.distance.angle_degrees(sigma_deg=10.0))
Source code in capturegraph-lib/capturegraph/scheduling/distance/angle.py
def angle_degrees(
    sigma_deg: float = 10.0,
    period: float = 360.0,
) -> CircularAngleDistanceFunction:
    """Create a circular angular distance function for degrees.

    Measures the shortest angular distance between two angles on a circle.
    By default, assumes 360° period (full rotation).

    Args:
        sigma_deg: Normalization factor in degrees. Angles within `sigma_deg`
            apart have distance < 1.0. Default is 10°.
        period: The period of the angle in degrees. Default is 360° (full circle).
            Use 180° for angles that wrap at ±90° (like latitude).

    Returns:
        A distance function `(angle_a, angle_b) -> float` with batch support.

    Example:
        ```python
        import capturegraph.scheduling as cgsh

        # Azimuth angles (0-360°)
        dist_fn = cgsh.distance.angle_degrees(sigma_deg=15.0)

        # Use with combine
        combined = cgsh.distance.combine(azimuth=cgsh.distance.angle_degrees(sigma_deg=10.0))
        ```
    """
    return CircularAngleDistanceFunction(sigma_deg, period)

angle_radians(sigma_rad=np.pi / 18, period=2 * np.pi) #

Create a circular angular distance function for radians.

Measures the shortest angular distance between two angles on a circle. By default, assumes 2π period (full rotation).

Parameters:

Name Type Description Default
sigma_rad float

Normalization factor in radians. Angles within sigma_rad apart have distance < 1.0. Default is π/18 (~10°).

pi / 18
period float

The period of the angle in radians. Default is 2π (full circle).

2 * pi

Returns:

Type Description
CircularAngleDistanceFunction

A distance function (angle_a, angle_b) -> float with batch support.

Example
import capturegraph.scheduling as cgsh
import numpy as np

# Angles in radians
dist_fn = cgsh.distance.angle_radians(sigma_rad=np.pi / 6)  # 30°
Source code in capturegraph-lib/capturegraph/scheduling/distance/angle.py
def angle_radians(
    sigma_rad: float = np.pi / 18,  # ~10 degrees
    period: float = 2 * np.pi,
) -> CircularAngleDistanceFunction:
    """Create a circular angular distance function for radians.

    Measures the shortest angular distance between two angles on a circle.
    By default, assumes 2π period (full rotation).

    Args:
        sigma_rad: Normalization factor in radians. Angles within `sigma_rad`
            apart have distance < 1.0. Default is π/18 (~10°).
        period: The period of the angle in radians. Default is 2π (full circle).

    Returns:
        A distance function `(angle_a, angle_b) -> float` with batch support.

    Example:
        ```python
        import capturegraph.scheduling as cgsh
        import numpy as np

        # Angles in radians
        dist_fn = cgsh.distance.angle_radians(sigma_rad=np.pi / 6)  # 30°
        ```
    """
    return CircularAngleDistanceFunction(sigma_rad, period)