I have a line between two points given as $(x_1, y_1)$ and $(x_2, y_2)$ in Python code:
class Line:
def __init__(self, x1, y1, x2, y2):
self.x1 = x1
self.y1 = y1
self.x2 = x2
self.y2 = y2
Now I'm trying to determine whether a given point $(x, y)$ is in the "hitbox" of this line, i.e. lies either directly on or close enough to the line. My current solution is inspired by the triangle inequality, in particular I check whether
$dist((x_1, y_1), (x, y)) + dist((x, y), (x_2, y_2)) - dist((x_1, y_1), (x_2, y_2)) < c$
for some $c$ (I use $c=1$ and my coordinates are all integers, but that's not really central to the question). However, this condition is much more lax at the middle of the line than at its ends.
Now, my AI code copilot recommended the following method:
def in_hitbox(self, x, y):
return np.linalg.norm(np.cross(np.array([self.x2 - self.x1, self.y2 - self.y1]), np.array([x - self.x1, y - self.y1]))) / np.linalg.norm(np.array([self.x2 - self.x1, self.y2 - self.y1])) < 1
Or translated into mathematical notation,
$\frac{\left\lvert\begin{bmatrix} x_2 - x_1 \\ y_2 - y_1 \end{bmatrix} \times \begin{bmatrix} x - x_1 \\ y - y_1 \end{bmatrix}\right\rvert_2}{\left\lvert\begin{bmatrix} x_2 - x_1 \\ y_2 - y_1 \end{bmatrix}\right\rvert_2} < 1$
I don't really understand this formula, but at least at a preliminary glance, it seems to work:
l1 = Line(0, 5, 10, 20)
print(l1.in_hitbox(5, 5)) # False
print(l1.in_hitbox(5, 12.5)) # True
print(l1.in_hitbox(5, 12)) # True
print(l1.in_hitbox(5, 11)) # True
print(l1.in_hitbox(5, 10)) # False
How does this formula actually work? What is given by the norm of the cross product between two vectors?
With the following illustration:
as per Sean's comment
$$ \frac{\left\lvert\begin{bmatrix} x_2 - x_1 \\ y_2 - y_1 \end{bmatrix} \times \begin{bmatrix} x - x_1 \\ y - y_1 \end{bmatrix}\right\rvert_2}{\left\lvert\begin{bmatrix} x_2 - x_1 \\ y_2 - y_1 \end{bmatrix}\right\rvert_2} = \left\lvert\begin{bmatrix} x - x_1 \\ y - y_1 \end{bmatrix}\right\rvert_2 \cdot sin\theta = \lvert\vec{AC}\rvert\cdot sin\theta, $$
which by the definition of the sine function gives the distance from the line to the point $C$ if the line is infinite (or if $C$ is within the region defined by perpendicular lines passing through $A$ and $B$).
In my case, with a finite line segment $AB$, I had to do some extra checks:
$$ dist = \begin{cases} \lvert\vec{AC}\rvert & \text{if }\vec{AB}\cdot\vec{AC}\le0\text{, i.e. } A \text{ is the closest point on the line to } C \text{;} \\ \lvert\vec{BC}\rvert & \text{if }\vec{AB}\cdot\vec{BC}\ge0\text{, i.e. } B \text{ is the closest point on the line to } C \text{;} \\ \frac{\lvert\vec{AB}\times\vec{AC}\rvert}{\lvert\vec{AB}\rvert} & \text{otherwise.} \end{cases} $$