"""Geometric utility functions for eye tracking simulation.
Provides line-line closest point, 2D line intersection, and other basic geometric operations.
"""
import numpy as np
from ..types import Point2D, Point3D, Vector3D
[docs]
def lines_closest_point(
p1: Point3D,
d1: Vector3D,
p2: Point3D,
d2: Vector3D,
) -> tuple[Point3D, Point3D]:
"""Find the closest points between two lines in 3D space.
Uses the minimum distance approach to find points on each line that are closest
to each other. For parallel lines, returns NaN points.
Args:
p1: Point on first line
d1: Direction vector of first line
p2: Point on second line
d2: Direction vector of second line
Returns:
Tuple of (x1, x2) where x1 is closest point on first line, x2 is closest point on second line.
Returns (NaN point, NaN point) if lines are parallel.
"""
# Set up linear system coefficient_matrix * alpha = b for closest point parameters
coefficient_matrix = np.array([[d1.dot(d1), -d2.dot(d1)], [d1.dot(d2), -d2.dot(d2)]])
b = np.array([-(p1 - p2).dot(d1), -(p1 - p2).dot(d2)])
try:
alpha = np.linalg.solve(coefficient_matrix, b)
# Compute closest points using structured type arithmetic
return p1 + d1 * alpha[0], p2 + d2 * alpha[1]
except np.linalg.LinAlgError:
# Lines are parallel - return NaN points
return Point3D(np.nan, np.nan, np.nan), Point3D(np.nan, np.nan, np.nan)
[docs]
def line_intersect_2d(p11: Point2D, p12: Point2D, p21: Point2D, p22: Point2D) -> Point2D:
"""Find the intersection point of two 2D lines.
Uses parametric line equations to solve for the intersection point.
Returns NaN point if lines are parallel.
Args:
p11: First point on first line
p12: Second point on first line
p21: First point on second line
p22: Second point on second line
Returns:
Intersection point. Returns Point2D(nan, nan) if lines are parallel.
"""
# Set up linear system for intersection parameters
dir1 = p12 - p11 # Direction vector of first line
dir2 = p22 - p21 # Direction vector of second line
coefficient_matrix = np.column_stack([np.array(dir1), -np.array(dir2)])
b = np.array(p21 - p11)
try:
t = np.linalg.solve(coefficient_matrix, b)
return p11 + dir1 * t[0] # Return intersection point
except np.linalg.LinAlgError:
return Point2D(np.nan, np.nan) # Parallel lines