Source code for madcubapy.utils.geometry
import numpy as np
__all__ = [
'polygon_area',
'polygon_signed_area',
'calculate_polygon_centroid',
]
[docs]
def polygon_area(vertices):
"""
Measure the area of a polygon's vertices.
Parameters
----------
vertices : `~numpy.ndarray`
Vertices of the polygon.
Returns
-------
area : `~float`
Area of the polygon.
"""
# Check that vertices is an array of points shaped (Nx2)
if (not isinstance(vertices, np.ndarray) or vertices.shape[-1] != 2):
raise ValueError(f'Invalid shape: {vertices.shape}. '
+ 'Last dimension has to be 2: (..., 2).')
x = vertices[:, 0]
y = vertices[:, 1]
x_next = np.roll(x, -1)
y_next = np.roll(y, -1)
area = 0.5 * abs(np.sum(x * y_next - x_next * y))
return area
[docs]
def polygon_signed_area(vertices):
"""
Compute the signed area of a polygon.
Positive area indicates counterclockwise vertex order,
negative area indicates clockwise order.
Parameters
----------
vertices : `~numpy.ndarray` of shape (N, 2)
Vertices of the polygon.
Returns
-------
signed_area : `~float`
Signed area of the polygon.
"""
# Check that vertices is an array of points shaped (Nx2)
if (not isinstance(vertices, np.ndarray) or vertices.shape[-1] != 2):
raise ValueError(f'Invalid shape: {vertices.shape}. '
+ 'Last dimension has to be 2: (..., 2).')
x = vertices[:, 0]
y = vertices[:, 1]
x_next = np.roll(x, -1)
y_next = np.roll(y, -1)
signed_area = 0.5 * np.sum(x * y_next - y * x_next)
return signed_area
[docs]
def calculate_polygon_centroid(vertices):
"""
Return the centroid of a polygon.
Parameters
----------
vertices : `~numpy.ndarray`
Vertices of the polygon.
Returns
-------
centroid : `~numpy.ndarray`
Centroid of the polygon.
"""
# Check that vertices is an array of points shaped (Nx2)
if (not isinstance(vertices, np.ndarray) or vertices.shape[-1] != 2):
raise ValueError(f'Invalid shape: {vertices.shape}. '
+ 'Last dimension has to be 2: (..., 2).')
x = vertices[:, 0]
y = vertices[:, 1]
signed_area = polygon_signed_area(vertices)
# Prevent division by zero
if np.isclose(signed_area, 0):
raise ValueError("The polygon's area is zero; cannot determine centroid.")
x_next = np.roll(x, -1)
y_next = np.roll(y, -1)
factor = (x * y_next - y * x_next )
centroid_x = np.sum((x + x_next) * factor) / (6 * signed_area)
centroid_y = np.sum((y + y_next) * factor) / (6 * signed_area)
centroid = np.array([centroid_x, centroid_y])
return centroid