use crate::Vec3;
use super::Plane;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Ray {
pub origin: Vec3,
pub direction: Vec3,
}
impl Ray {
#[inline]
pub fn new(origin: Vec3, direction: Vec3) -> Self {
Self {
origin,
direction: direction.normalize(),
}
}
#[inline]
pub fn at(&self, t: f32) -> Vec3 {
self.origin + self.direction * t
}
#[inline]
pub fn closest_point_to(&self, point: Vec3) -> Vec3 {
let to_point = point - self.origin;
let t = self.direction.dot(to_point);
self.at(t.max(0.0))
}
#[inline]
pub fn distance_to_point(&self, point: Vec3) -> f32 {
let closest = self.closest_point_to(point);
(point - closest).length()
}
#[inline]
pub fn intersect_plane(&self, plane: &Plane) -> Option<f32> {
let denom = self.direction.dot(plane.normal);
if denom.abs() < f32::EPSILON {
return None;
}
let t = -(plane.normal.dot(self.origin) + plane.d) / denom;
if t >= 0.0 {
Some(t)
} else {
None
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ray_at() {
let ray = Ray::new(Vec3::ZERO, Vec3::X);
assert_eq!(ray.at(5.0), Vec3::new(5.0, 0.0, 0.0));
}
#[test]
fn test_ray_closest_point() {
let ray = Ray::new(Vec3::ZERO, Vec3::X);
let point = Vec3::new(5.0, 3.0, 0.0);
let closest = ray.closest_point_to(point);
assert_eq!(closest, Vec3::new(5.0, 0.0, 0.0));
}
}