2022-10-05 22:16:26 +00:00
|
|
|
use crate::Vec3;
|
|
|
|
|
|
|
|
/// A ray is an infinite line starting at `origin`, going in `direction`.
|
2022-10-31 16:12:15 +00:00
|
|
|
#[derive(Default, Clone, Copy, Debug, PartialEq)]
|
|
|
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
2022-10-05 22:16:26 +00:00
|
|
|
pub struct Ray {
|
|
|
|
/// The origin of the ray.
|
|
|
|
pub origin: Vec3,
|
2022-12-02 02:36:44 +00:00
|
|
|
/// A normalized vector representing the direction of the ray.
|
2022-10-05 22:16:26 +00:00
|
|
|
pub direction: Vec3,
|
|
|
|
}
|
2022-12-02 02:36:44 +00:00
|
|
|
|
|
|
|
impl Ray {
|
|
|
|
/// Returns the distance to the plane if the ray intersects it.
|
|
|
|
#[inline]
|
|
|
|
pub fn intersect_plane(&self, plane_origin: Vec3, plane_normal: Vec3) -> Option<f32> {
|
|
|
|
let denominator = plane_normal.dot(self.direction);
|
|
|
|
if denominator.abs() > f32::EPSILON {
|
|
|
|
let distance = (plane_origin - self.origin).dot(plane_normal) / denominator;
|
2022-12-05 22:49:06 +00:00
|
|
|
if distance > f32::EPSILON {
|
2022-12-02 02:36:44 +00:00
|
|
|
return Some(distance);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Retrieve a point at the given distance along the ray.
|
|
|
|
#[inline]
|
|
|
|
pub fn get_point(&self, distance: f32) -> Vec3 {
|
|
|
|
self.origin + self.direction * distance
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
2022-12-05 22:49:06 +00:00
|
|
|
mod tests {
|
2022-12-02 02:36:44 +00:00
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
2022-12-05 22:49:06 +00:00
|
|
|
fn intersect_plane() {
|
2022-12-02 02:36:44 +00:00
|
|
|
let ray = Ray {
|
|
|
|
origin: Vec3::ZERO,
|
|
|
|
direction: Vec3::Z,
|
|
|
|
};
|
|
|
|
|
2022-12-05 22:49:06 +00:00
|
|
|
// Orthogonal, and test that an inverse plane_normal has the same result
|
2022-12-02 02:36:44 +00:00
|
|
|
assert_eq!(Some(1.), ray.intersect_plane(Vec3::Z, Vec3::Z));
|
|
|
|
assert_eq!(Some(1.), ray.intersect_plane(Vec3::Z, Vec3::NEG_Z));
|
|
|
|
assert_eq!(None, ray.intersect_plane(Vec3::NEG_Z, Vec3::Z));
|
|
|
|
assert_eq!(None, ray.intersect_plane(Vec3::NEG_Z, Vec3::NEG_Z));
|
|
|
|
|
|
|
|
// Diagonal
|
|
|
|
assert_eq!(Some(1.), ray.intersect_plane(Vec3::Z, Vec3::ONE));
|
|
|
|
assert_eq!(None, ray.intersect_plane(Vec3::NEG_Z, Vec3::ONE));
|
|
|
|
|
2022-12-05 22:49:06 +00:00
|
|
|
// Parallel
|
2022-12-02 02:36:44 +00:00
|
|
|
assert_eq!(None, ray.intersect_plane(Vec3::X, Vec3::X));
|
|
|
|
|
2022-12-05 22:49:06 +00:00
|
|
|
// Parallel with simulated rounding error
|
2022-12-02 02:36:44 +00:00
|
|
|
assert_eq!(
|
|
|
|
None,
|
|
|
|
ray.intersect_plane(Vec3::X, Vec3::X + Vec3::Z * f32::EPSILON)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|