HyperView / src /hyperview /core /selection.py
morozovdd's picture
feat: add HyperView app for space
23680f2
"""Selection / geometry helpers.
This module contains small, backend-agnostic utilities used by selection endpoints
(e.g. lasso selection over 2D embeddings).
"""
from __future__ import annotations
import numpy as np
def points_in_polygon(points_xy: np.ndarray, polygon_xy: np.ndarray) -> np.ndarray:
"""Vectorized point-in-polygon (even-odd rule / ray casting).
Args:
points_xy: Array of shape (m, 2) with point coordinates.
polygon_xy: Array of shape (n, 2) with polygon vertices.
Returns:
Boolean mask of length m, True where point lies inside polygon.
Notes:
Boundary points may be classified as outside depending on floating point
ties (common for lasso selection tools).
"""
if polygon_xy.shape[0] < 3:
return np.zeros((points_xy.shape[0],), dtype=bool)
x = points_xy[:, 0]
y = points_xy[:, 1]
poly_x = polygon_xy[:, 0]
poly_y = polygon_xy[:, 1]
inside = np.zeros((points_xy.shape[0],), dtype=bool)
j = polygon_xy.shape[0] - 1
for i in range(polygon_xy.shape[0]):
xi = poly_x[i]
yi = poly_y[i]
xj = poly_x[j]
yj = poly_y[j]
# Half-open y-interval to avoid double-counting vertices.
intersects = (yi > y) != (yj > y)
denom = yj - yi
# denom == 0 => intersects is always False; add tiny epsilon to avoid warnings.
x_intersect = (xj - xi) * (y - yi) / (denom + 1e-30) + xi
inside ^= intersects & (x < x_intersect)
j = i
return inside