use crate::{
base_math::{min_max, quadratic_solutions},
Real, Vector2,
};
#[derive(Debug, Copy, Clone)]
pub enum LineCircleIntr<T>
where
T: Real,
{
NoIntersect,
TangentIntersect {
t0: T,
},
TwoIntersects {
t0: T,
t1: T,
},
}
pub fn line_circle_intr<T>(
p0: Vector2<T>,
p1: Vector2<T>,
radius: T,
circle_center: Vector2<T>,
) -> LineCircleIntr<T>
where
T: Real,
{
use LineCircleIntr::*;
let dx = p1.x - p0.x;
let dy = p1.y - p0.y;
let h = circle_center.x;
let k = circle_center.y;
let a_quad = dx * dx + dy * dy;
if a_quad.fuzzy_eq_zero() {
let xh = p0.x - h;
let yk = p0.y - k;
if (xh * xh + yk * yk).fuzzy_eq(radius * radius) {
return TangentIntersect { t0: T::zero() };
}
return NoIntersect;
}
let b_quad = T::two() * (dx * (p0.x - h) + dy * (p0.y - k));
let c_quad = (p0.x * p0.x - T::two() * h * p0.x + h * h)
+ (p0.y * p0.y - T::two() * k * p0.y + k * k)
- radius * radius;
let discriminant = b_quad * b_quad - T::four() * a_quad * c_quad;
if discriminant.fuzzy_eq_zero() {
return TangentIntersect {
t0: -b_quad / (T::two() * a_quad),
};
}
if discriminant < T::zero() {
return NoIntersect;
}
let (sol1, sol2) = quadratic_solutions(a_quad, b_quad, c_quad, discriminant);
let (t0, t1) = min_max(sol1, sol2);
TwoIntersects { t0, t1 }
}