+ "file_text": "#[derive(Debug, Clone, Copy)]\npub struct Vec3 {\n pub x: f32,\n pub y: f32,\n pub z: f32,\n}\n\nimpl Vec3 {\n pub fn new(x: f32, y: f32, z: f32) -> Self {\n Vec3 { x, y, z }\n }\n\n pub fn min(&self, other: &Vec3) -> Vec3 {\n Vec3 {\n x: self.x.min(other.x),\n y: self.y.min(other.y),\n z: self.z.min(other.z),\n }\n }\n\n pub fn max(&self, other: &Vec3) -> Vec3 {\n Vec3 {\n x: self.x.max(other.x),\n y: self.y.max(other.y),\n z: self.z.max(other.z),\n }\n }\n}\n\n#[derive(Debug)]\npub struct Ray {\n pub origin: Vec3,\n pub direction: Vec3,\n}\n\nimpl Ray {\n pub fn new(origin: Vec3, direction: Vec3) -> Self {\n Ray { origin, direction }\n }\n}\n\n#[derive(Debug)]\npub struct Cube {\n pub min: Vec3,\n pub max: Vec3,\n}\n\nimpl Cube {\n pub fn new(min: Vec3, max: Vec3) -> Self {\n Cube { min, max }\n }\n\n // Returns (t_min, t_max) for intersection. If t_min > t_max, there is no intersection\n pub fn intersect(&self, ray: &Ray) -> (f32, f32) {\n let mut t_min = f32::NEG_INFINITY;\n let mut t_max = f32::INFINITY;\n\n // Check intersection with all three slabs\n for i in 0..3 {\n let (origin, direction) = match i {\n 0 => (ray.origin.x, ray.direction.x),\n 1 => (ray.origin.y, ray.direction.y),\n 2 => (ray.origin.z, ray.direction.z),\n _ => unreachable!(),\n };\n\n let (min_val, max_val) = match i {\n 0 => (self.min.x, self.max.x),\n 1 => (self.min.y, self.max.y),\n 2 => (self.min.z, self.max.z),\n _ => unreachable!(),\n };\n\n if direction.abs() < f32::EPSILON {\n // Ray is parallel to slab. No hit if origin not within slab\n if origin < min_val || origin > max_val {\n return (1.0, -1.0); // No intersection\n }\n } else {\n // Compute intersection t value of ray with near and far plane of slab\n let t1 = (min_val - origin) / direction;\n let t2 = (max_val - origin) / direction;\n\n // Make t1 be intersection with near plane, t2 with far plane\n let (t1, t2) = if t1 > t2 { (t2, t1) } else { (t1, t2) };\n\n // Update t_min and t_max\n t_min = t_min.max(t1);\n t_max = t_max.min(t2);\n\n // Exit with no collision as soon as slab intersection becomes empty\n if t_min > t_max {\n return (1.0, -1.0);\n }\n }\n }\n\n (t_min, t_max)\n }\n}\n\n#[cfg(test)]\nmod tests {\n use super::*;\n\n #[test]\n fn test_ray_cube_intersection() {\n // Create a cube centered at origin with size 2\n let cube = Cube::new(\n Vec3::new(-1.0, -1.0, -1.0),\n Vec3::new(1.0, 1.0, 1.0),\n );\n\n // Ray starting outside the cube and pointing towards it\n let ray = Ray::new(\n Vec3::new(-2.0, 0.0, 0.0),\n Vec3::new(1.0, 0.0, 0.0),\n );\n\n let (t_min, t_max) = cube.intersect(&ray);\n assert!(t_min <= t_max);\n assert_eq!(t_min, 1.0); // Should hit at x = -1\n assert_eq!(t_max, 3.0); // Should exit at x = 1\n\n // Ray missing the cube\n let ray_miss = Ray::new(\n Vec3::new(-2.0, 2.0, 0.0),\n Vec3::new(1.0, 0.0, 0.0),\n );\n\n let (t_min, t_max) = cube.intersect(&ray_miss);\n assert!(t_min > t_max); // Indicates no intersection\n }\n}\n\n"
0 commit comments