#![cfg(feature = "collision")]
use gemath::*;
#[cfg(test)]
mod tests {
use super::*;
const EPS: f32 = if cfg!(feature = "libm") { 1e-5 } else { 1e-6 };
#[test]
fn segment2_intersection_basic_and_collinear() {
let a: Segment2<(), ()> = Segment2::new(Vec2::new(0.0, 0.0), Vec2::new(2.0, 0.0));
let b: Segment2<(), ()> = Segment2::new(Vec2::new(1.0, -1.0), Vec2::new(1.0, 1.0));
assert!(segment2_intersects(a, b));
let p = segment2_intersection_point(a, b).unwrap();
assert!((p - Vec2::<(), ()>::new(1.0, 0.0)).length() < 1e-6);
let c: Segment2<(), ()> = Segment2::new(Vec2::new(0.0, 0.0), Vec2::new(1.0, 0.0));
let d: Segment2<(), ()> = Segment2::new(Vec2::new(1.0, 0.0), Vec2::new(2.0, 0.0));
assert!(segment2_intersects(c, d));
let p2 = segment2_intersection_point(c, d).unwrap();
assert!((p2 - Vec2::<(), ()>::new(1.0, 0.0)).length() < 1e-6);
let e: Segment2<(), ()> = Segment2::new(Vec2::new(0.0, 0.0), Vec2::new(2.0, 0.0));
let f: Segment2<(), ()> = Segment2::new(Vec2::new(1.0, 0.0), Vec2::new(3.0, 0.0));
assert!(segment2_intersects(e, f));
assert!(segment2_intersection_point(e, f).is_none());
}
#[test]
fn circle_rect2_and_aabb2_intersects() {
let rect: Rect2<(), ()> = Rect2::new(Vec2::new(0.0, 0.0), Vec2::new(1.0, 1.0));
let circle_inside: Circle<(), ()> = Circle::new(Vec2::new(0.5, 0.5), 0.1);
assert!(circle_rect2_intersects(circle_inside, &rect));
let circle_tangent: Circle<(), ()> = Circle::new(Vec2::new(2.0, 0.5), 1.0);
assert!(circle_rect2_intersects(circle_tangent, &rect));
let circle_far: Circle<(), ()> = Circle::new(Vec2::new(10.0, 10.0), 1.0);
assert!(!circle_rect2_intersects(circle_far, &rect));
let aabb: Aabb2<(), ()> = Aabb2::from_min_max(Vec2::new(0.0, 0.0), Vec2::new(1.0, 1.0));
assert!(circle_aabb2_intersects(circle_inside, &aabb));
assert!(circle_aabb2_intersects(circle_tangent, &aabb));
assert!(!circle_aabb2_intersects(circle_far, &aabb));
}
#[test]
fn sphere_aabb3_and_rect3_intersects() {
let aabb: Aabb3<(), ()> = Aabb3::from_min_max(Vec3::new(-1.0, -1.0, -1.0), Vec3::new(1.0, 1.0, 1.0));
let rect: Rect3<(), ()> = Rect3::from_min_max(Vec3::new(-1.0, -1.0, -1.0), Vec3::new(1.0, 1.0, 1.0));
let s_inside: Sphere<(), ()> = Sphere::new(Vec3::new(0.0, 0.0, 0.0), 0.5);
assert!(sphere_aabb3_intersects(s_inside, &aabb));
assert!(sphere_rect3_intersects(s_inside, &rect));
let s_tangent: Sphere<(), ()> = Sphere::new(Vec3::new(2.0, 0.0, 0.0), 1.0);
assert!(sphere_aabb3_intersects(s_tangent, &aabb));
assert!(sphere_rect3_intersects(s_tangent, &rect));
let s_far: Sphere<(), ()> = Sphere::new(Vec3::new(10.0, 0.0, 0.0), 1.0);
assert!(!sphere_aabb3_intersects(s_far, &aabb));
assert!(!sphere_rect3_intersects(s_far, &rect));
}
#[test]
fn ray_circle_and_ray_sphere_intersect_t() {
let circle: Circle<(), ()> = Circle::new(Vec2::new(0.0, 0.0), 1.0);
let ray: Ray2<(), ()> = Ray2::new(Vec2::new(-2.0, 0.0), Vec2::new(1.0, 0.0));
let t = ray2_circle_intersect(ray, circle).unwrap();
assert!((t - 1.0).abs() < 1e-6);
let ray_inside: Ray2<(), ()> = Ray2::new(Vec2::new(0.0, 0.0), Vec2::new(1.0, 0.0));
let t2 = ray2_circle_intersect(ray_inside, circle).unwrap();
assert!((t2 - 1.0).abs() < 1e-6);
let ray_miss: Ray2<(), ()> = Ray2::new(Vec2::new(-2.0, 2.0), Vec2::new(1.0, 0.0));
assert!(ray2_circle_intersect(ray_miss, circle).is_none());
let sphere: Sphere<(), ()> = Sphere::new(Vec3::new(0.0, 0.0, 0.0), 1.0);
let ray3: Ray3<(), ()> = Ray3::new(Vec3::new(-2.0, 0.0, 0.0), Vec3::new(1.0, 0.0, 0.0));
let t3 = ray3_sphere_intersect(ray3, sphere).unwrap();
assert!((t3 - 1.0).abs() < 1e-6);
}
#[test]
fn raycast_hit_results_have_t_point_and_normal() {
let circle: Circle<(), ()> = Circle::new(Vec2::new(0.0, 0.0), 1.0);
let ray: Ray2<(), ()> = Ray2::new(Vec2::new(-2.0, 0.0), Vec2::new(1.0, 0.0));
let hit = ray2_circle_cast(ray, circle).unwrap();
assert!((hit.t - 1.0).abs() < EPS);
assert!((hit.point - Vec2::<(), ()>::new(-1.0, 0.0)).length() < EPS);
assert!((hit.normal - Vec2::<(), ()>::new(-1.0, 0.0)).length() < EPS);
let ray_tangent: Ray2<(), ()> = Ray2::new(Vec2::new(-2.0, 1.0), Vec2::new(1.0, 0.0));
let hit_tangent = ray2_circle_cast(ray_tangent, circle).unwrap();
assert!((hit_tangent.t - 2.0).abs() < EPS);
assert!((hit_tangent.point - Vec2::<(), ()>::new(0.0, 1.0)).length() < EPS);
assert!((hit_tangent.normal - Vec2::<(), ()>::new(0.0, 1.0)).length() < EPS);
let ray_inside: Ray2<(), ()> = Ray2::new(Vec2::new(0.0, 0.0), Vec2::new(1.0, 0.0));
let hit_inside = ray2_circle_cast(ray_inside, circle).unwrap();
assert!((hit_inside.t - 1.0).abs() < EPS);
assert!((hit_inside.point - Vec2::<(), ()>::new(1.0, 0.0)).length() < EPS);
assert!((hit_inside.normal - Vec2::<(), ()>::new(1.0, 0.0)).length() < EPS);
let ray_miss: Ray2<(), ()> = Ray2::new(Vec2::new(-2.0, 2.0), Vec2::new(1.0, 0.0));
assert!(ray2_circle_cast(ray_miss, circle).is_none());
let sphere: Sphere<(), ()> = Sphere::new(Vec3::new(0.0, 0.0, 0.0), 1.0);
let ray3: Ray3<(), ()> = Ray3::new(Vec3::new(-2.0, 0.0, 0.0), Vec3::new(1.0, 0.0, 0.0));
let hit3 = ray3_sphere_cast(ray3, sphere).unwrap();
assert!((hit3.t - 1.0).abs() < EPS);
assert!((hit3.point - Vec3::<(), ()>::new(-1.0, 0.0, 0.0)).length() < EPS);
assert!((hit3.normal - Vec3::<(), ()>::new(-1.0, 0.0, 0.0)).length() < EPS);
let ray3_tangent: Ray3<(), ()> = Ray3::new(Vec3::new(-2.0, 1.0, 0.0), Vec3::new(1.0, 0.0, 0.0));
let hit3_tangent = ray3_sphere_cast(ray3_tangent, sphere).unwrap();
assert!((hit3_tangent.t - 2.0).abs() < EPS);
assert!((hit3_tangent.point - Vec3::<(), ()>::new(0.0, 1.0, 0.0)).length() < EPS);
assert!((hit3_tangent.normal - Vec3::<(), ()>::new(0.0, 1.0, 0.0)).length() < EPS);
let ray3_inside: Ray3<(), ()> = Ray3::new(Vec3::new(0.0, 0.0, 0.5), Vec3::new(0.0, 0.0, 1.0));
let hit3_inside = ray3_sphere_cast(ray3_inside, sphere).unwrap();
assert!((hit3_inside.t - 0.5).abs() < EPS);
assert!((hit3_inside.point - Vec3::<(), ()>::new(0.0, 0.0, 1.0)).length() < EPS);
assert!((hit3_inside.normal - Vec3::<(), ()>::new(0.0, 0.0, 1.0)).length() < EPS);
let ray3_miss: Ray3<(), ()> = Ray3::new(Vec3::new(-2.0, 2.0, 0.0), Vec3::new(1.0, 0.0, 0.0));
assert!(ray3_sphere_cast(ray3_miss, sphere).is_none());
}
#[test]
fn segment_circle_and_segment_sphere_intersects() {
let seg2: Segment2<(), ()> = Segment2::new(Vec2::new(0.0, 0.0), Vec2::new(2.0, 0.0));
let c_hit: Circle<(), ()> = Circle::new(Vec2::new(1.0, 0.25), 0.5);
let c_miss: Circle<(), ()> = Circle::new(Vec2::new(3.0, 0.0), 0.5);
assert!(segment2_circle_intersects(seg2, c_hit));
assert!(!segment2_circle_intersects(seg2, c_miss));
let seg3: Segment3<(), ()> = Segment3::new(Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 2.0));
let s_hit: Sphere<(), ()> = Sphere::new(Vec3::new(0.25, 0.0, 1.0), 0.5);
let s_miss: Sphere<(), ()> = Sphere::new(Vec3::new(3.0, 0.0, 1.0), 0.5);
assert!(segment3_sphere_intersects(seg3, s_hit));
assert!(!segment3_sphere_intersects(seg3, s_miss));
}
}