# Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
"""
.. Coordinates Algorithms (see parent package :mod:`cdl.algorithms`)
"""
# pylint: disable=invalid-name # Allows short reference names like x, y, ...
from __future__ import annotations
import numpy as np
[docs]
def circle_to_diameter(
xc: float, yc: float, r: float
) -> tuple[float, float, float, float]:
"""Convert circle center and radius to X diameter coordinates
Args:
xc: Circle center X coordinate
yc: Circle center Y coordinate
r: Circle radius
Returns:
tuple: Circle X diameter coordinates
"""
return xc - r, yc, xc + r, yc
[docs]
def array_circle_to_diameter(data: np.ndarray) -> np.ndarray:
"""Convert circle center and radius to X diameter coordinates (array version)
Args:
data: Circle center and radius, in the form of a 2D array (N, 3)
Returns:
Circle X diameter coordinates, in the form of a 2D array (N, 4)
"""
xc, yc, r = data[:, 0], data[:, 1], data[:, 2]
x_start = xc - r
x_end = xc + r
result = np.column_stack((x_start, yc, x_end, yc)).astype(float)
return result
[docs]
def circle_to_center_radius(
x0: float, y0: float, x1: float, y1: float
) -> tuple[float, float, float]:
"""Convert circle X diameter coordinates to center and radius
Args:
x0: Diameter start X coordinate
y0: Diameter start Y coordinate
x1: Diameter end X coordinate
y1: Diameter end Y coordinate
Returns:
tuple: Circle center and radius
"""
xc, yc = (x0 + x1) / 2, (y0 + y1) / 2
r = np.sqrt((x1 - x0) ** 2 + (y1 - y0) ** 2) / 2
return xc, yc, r
[docs]
def array_circle_to_center_radius(data: np.ndarray) -> np.ndarray:
"""Convert circle X diameter coordinates to center and radius (array version)
Args:
data: Circle X diameter coordinates, in the form of a 2D array (N, 4)
Returns:
Circle center and radius, in the form of a 2D array (N, 3)
"""
x0, y0, x1, y1 = data[:, 0], data[:, 1], data[:, 2], data[:, 3]
xc, yc = (x0 + x1) / 2, (y0 + y1) / 2
r = np.sqrt((x1 - x0) ** 2 + (y1 - y0) ** 2) / 2
result = np.column_stack((xc, yc, r)).astype(float)
return result
[docs]
def ellipse_to_diameters(
xc: float, yc: float, a: float, b: float, theta: float
) -> tuple[float, float, float, float, float, float, float, float]:
"""Convert ellipse center, axes and angle to X/Y diameters coordinates
Args:
xc: Ellipse center X coordinate
yc: Ellipse center Y coordinate
a: Ellipse half larger axis
b: Ellipse half smaller axis
theta: Ellipse angle
Returns:
Ellipse X/Y diameters (major/minor axes) coordinates
"""
dxa, dya = a * np.cos(theta), a * np.sin(theta)
dxb, dyb = b * np.sin(theta), b * np.cos(theta)
x0, y0, x1, y1 = xc - dxa, yc - dya, xc + dxa, yc + dya
x2, y2, x3, y3 = xc - dxb, yc - dyb, xc + dxb, yc + dyb
return x0, y0, x1, y1, x2, y2, x3, y3
[docs]
def array_ellipse_to_diameters(data: np.ndarray) -> np.ndarray:
"""Convert ellipse center, axes and angle to X/Y diameters coordinates
(array version)
Args:
data: Ellipse center, axes and angle, in the form of a 2D array (N, 5)
Returns:
Ellipse X/Y diameters (major/minor axes) coordinates,
in the form of a 2D array (N, 8)
"""
xc, yc, a, b, theta = data[:, 0], data[:, 1], data[:, 2], data[:, 3], data[:, 4]
dxa, dya = a * np.cos(theta), a * np.sin(theta)
dxb, dyb = b * np.sin(theta), b * np.cos(theta)
x0, y0, x1, y1 = xc - dxa, yc - dya, xc + dxa, yc + dya
x2, y2, x3, y3 = xc - dxb, yc - dyb, xc + dxb, yc + dyb
result = np.column_stack((x0, y0, x1, y1, x2, y2, x3, y3)).astype(float)
return result
[docs]
def ellipse_to_center_axes_angle(
x0: float,
y0: float,
x1: float,
y1: float,
x2: float,
y2: float,
x3: float,
y3: float,
) -> tuple[float, float, float, float, float]:
"""Convert ellipse X/Y diameters coordinates to center, axes and angle
Args:
x0: major axis start X coordinate
y0: major axis start Y coordinate
x1: major axis end X coordinate
y1: major axis end Y coordinate
x2: minor axis start X coordinate
y2: minor axis start Y coordinate
x3: minor axis end X coordinate
y3: minor axis end Y coordinate
Returns:
Ellipse center, axes and angle
"""
xc, yc = (x0 + x1) / 2, (y0 + y1) / 2
a = np.sqrt((x1 - x0) ** 2 + (y1 - y0) ** 2) / 2
b = np.sqrt((x3 - x2) ** 2 + (y3 - y2) ** 2) / 2
theta = np.arctan2(y1 - y0, x1 - x0)
return xc, yc, a, b, theta
[docs]
def array_ellipse_to_center_axes_angle(data: np.ndarray) -> np.ndarray:
"""Convert ellipse X/Y diameters coordinates to center, axes and angle
(array version)
Args:
data: Ellipse X/Y diameters coordinates, in the form of a 2D array (N, 8)
Returns:
Ellipse center, axes and angle, in the form of a 2D array (N, 5)
"""
x0, y0, x1, y1, x2, y2, x3, y3 = (
data[:, 0],
data[:, 1],
data[:, 2],
data[:, 3],
data[:, 4],
data[:, 5],
data[:, 6],
data[:, 7],
)
xc, yc = (x0 + x1) / 2, (y0 + y1) / 2
a = np.sqrt((x1 - x0) ** 2 + (y1 - y0) ** 2) / 2
b = np.sqrt((x3 - x2) ** 2 + (y3 - y2) ** 2) / 2
theta = np.arctan2(y1 - y0, x1 - x0)
result = np.column_stack((xc, yc, a, b, theta)).astype(float)
return result