use super::{Vector2, base_math::parametric_from_point};
use crate::core::traits::Real;
#[derive(Debug, Copy, Clone)]
pub enum LineLineIntr<T>
where
T: Real,
{
NoIntersect,
TrueIntersect {
seg1_t: T,
seg2_t: T,
},
Overlapping {
seg2_t0: T,
seg2_t1: T,
},
FalseIntersect {
seg1_t: T,
seg2_t: T,
},
}
pub fn line_line_intr<T>(
v1: Vector2<T>,
v2: Vector2<T>,
u1: Vector2<T>,
u2: Vector2<T>,
epsilon: T,
) -> LineLineIntr<T>
where
T: Real,
{
use LineLineIntr::*;
let v = v2 - v1;
let u = u2 - u1;
let v_pdot_u = v.perp_dot(u);
let w = v1 - u1;
let eps = epsilon;
let seg1_length = (v2 - v1).length();
let seg2_length = (u2 - u1).length();
if !v_pdot_u.fuzzy_eq_zero_eps(eps) {
let seg1_t = u.perp_dot(w) / v_pdot_u;
let seg2_t = v.perp_dot(w) / v_pdot_u;
if !(seg1_t * seg1_length).fuzzy_in_range_eps(T::zero(), seg1_length, eps)
|| !(seg2_t * seg2_length).fuzzy_in_range_eps(T::zero(), seg2_length, eps)
{
return FalseIntersect { seg1_t, seg2_t };
}
return TrueIntersect { seg1_t, seg2_t };
}
let v_pdot_w = v.perp_dot(w);
let u_pdot_w = u.perp_dot(w);
if !v_pdot_w.fuzzy_eq_zero_eps(eps) || !u_pdot_w.fuzzy_eq_zero_eps(eps) {
return NoIntersect;
}
let v_is_point = v1.fuzzy_eq_eps(v2, eps);
let u_is_point = u1.fuzzy_eq_eps(u2, eps);
if v_is_point && u_is_point {
if v1.fuzzy_eq_eps(u1, eps) {
return TrueIntersect {
seg1_t: T::zero(),
seg2_t: T::zero(),
};
}
return NoIntersect;
}
if v_is_point {
let seg2_t = parametric_from_point(u1, u2, v1, eps);
if (seg2_t * seg2_length).fuzzy_in_range_eps(T::zero(), seg2_length, eps) {
return TrueIntersect {
seg1_t: T::zero(),
seg2_t,
};
}
return NoIntersect;
}
if u_is_point {
let seg1_t = parametric_from_point(v1, v2, u1, eps);
if (seg1_t * seg1_length).fuzzy_in_range_eps(T::zero(), seg1_length, eps) {
return TrueIntersect {
seg1_t,
seg2_t: T::zero(),
};
}
return NoIntersect;
}
let w2 = v2 - u1;
let (mut seg2_t0, mut seg2_t1) = if u.x.fuzzy_eq_zero_eps(eps) {
(w.y / u.y, w2.y / u.y)
} else {
(w.x / u.x, w2.x / u.x)
};
if seg2_t0 > seg2_t1 {
std::mem::swap(&mut seg2_t0, &mut seg2_t1);
}
if !(seg2_t0 * seg2_length).fuzzy_lt_eps(seg2_length, eps)
|| !(seg2_t1 * seg2_length).fuzzy_gt_eps(T::zero(), eps)
{
return NoIntersect;
}
seg2_t0 = num_traits::real::Real::max(seg2_t0, T::zero());
seg2_t1 = num_traits::real::Real::min(seg2_t1, T::one());
if ((seg2_t1 - seg2_t0) * seg2_length).fuzzy_eq_zero_eps(eps) {
let seg1_t = if v1.fuzzy_eq_eps(u1, eps) || v1.fuzzy_eq_eps(u2, eps) {
T::zero()
} else {
T::one()
};
return TrueIntersect {
seg1_t,
seg2_t: seg2_t0,
};
}
Overlapping { seg2_t0, seg2_t1 }
}