use super::*;
#[test]
fn test_ray_hits_triangle_from_outside() {
let triangle = Triangle3 {
p: Point3(0.0, 0.0, 0.0),
u: Vec3(1.0, 0.0, 0.0),
v: Vec3(0.0, 1.0, 0.0),
};
let ray = Ray3 {
origin: Point3(0.25, 0.25, 1.0),
direction: Vec3(0.0, 0.0, -1.0),
distance: Interval(0.0, f64::INFINITY),
};
let result = triangle.trace(&ray);
assert!(result.is_some());
assert!((result.unwrap().distance - 1.0).abs() < 1e-6);
assert_eq!(result.unwrap().normal, Vec3(0.0, 0.0, 1.0));
}
#[test]
fn test_ray_misses_triangle() {
let triangle = Triangle3 {
p: Point3(0.0, 0.0, 0.0),
u: Vec3(1.0, 0.0, 0.0),
v: Vec3(0.0, 1.0, 0.0),
};
let ray = Ray3 {
origin: Point3(1.1, 1.1, 1.0),
direction: Vec3(0.0, 0.0, -1.0),
distance: Interval(0.0, f64::INFINITY),
};
let result = triangle.trace(&ray);
assert!(result.is_none());
}
#[test]
fn test_ray_originates_inside_triangle() {
let triangle = Triangle3 {
p: Point3(0.0, 0.0, 0.0),
u: Vec3(1.0, 0.0, 0.0),
v: Vec3(0.0, 1.0, 0.0),
};
let ray = Ray3 {
origin: Point3(0.25, 0.25, -1.0),
direction: Vec3(0.0, 0.0, 1.0),
distance: Interval(0.0, f64::INFINITY),
};
let result = triangle.trace(&ray);
assert!(result.is_some());
assert!((result.unwrap().distance - 1.0).abs() < 1e-6);
assert_eq!(result.unwrap().normal, Vec3(0.0, 0.0, -1.0));
}
#[test]
fn test_trace_random_triangles() {
let mut rng = urandom::new();
for _ in 0..1000 {
let p1 = Point3(rng.next_f32(), rng.next_f32(), rng.next_f32());
let p2 = Point3(rng.next_f32(), rng.next_f32(), rng.next_f32());
let p3 = Point3(rng.next_f32(), rng.next_f32(), rng.next_f32());
let triangle = Triangle3::points(p1, p2, p3);
if triangle.area() < 1e-6 {
continue;
}
let direction = -triangle.plane().normal;
let origin = triangle.centroid() + direction;
let mut ray = Ray3 { origin, direction, distance: Interval(0.0, f32::INFINITY) };
let hit = ray.trace(&triangle);
assert!(hit.is_none(), "Ray should not hit the triangle when moving away from it");
let x = rng.range(-0.5..1.5);
let y = rng.range(-0.5..1.5);
let p = triangle.p + triangle.u * x + triangle.v * y;
ray.direction = (p - ray.origin).norm();
let hit = ray.trace(&triangle);
let is_inside = x > 0.01 && x < 0.99 && y > 0.01 && y < 0.99 && x + y < 0.99;
if is_inside {
assert!(hit.is_some(), "Ray should hit the triangle when moving towards it {x} {y}");
}
let is_outside = x < -0.01 || x > 1.01 || y < -0.01 || y > 1.01 || x + y > 1.01;
if is_outside {
assert!(hit.is_none(), "Ray should miss the triangle when moving away from it {x} {y}");
}
if let Some(hit) = hit {
let d = triangle.plane().distance(hit.point);
assert!(d.abs() < 1e-4, "Hit point d={d} should be on the triangle's plane");
}
}
}