Skip to main content

collide_ray/
lib.rs

1#![deny(missing_docs)]
2
3//! Ray collider implementation for the `collide` crate.
4//!
5//! A ray is defined by an origin and a direction vector.
6//! It extends infinitely in the direction from the origin.
7
8use collide::CollisionInfo;
9use inner_space::{InnerSpace, VectorSpace};
10use scalars::{Sqrt, Zero};
11
12/// A ray defined by an origin point and a direction vector.
13#[derive(Copy, Clone, Debug)]
14pub struct Ray<V: VectorSpace> {
15    /// The starting point of the ray.
16    pub origin: V,
17    /// The direction the ray extends in.
18    pub direction: V,
19}
20
21impl<V: Copy + InnerSpace> Ray<V> {
22    /// Creates a new ray.
23    pub fn new(origin: V, direction: V) -> Self {
24        Self { origin, direction }
25    }
26
27    /// Intersects this ray with a sphere defined by center and radius.
28    /// Returns the ray parameter and collision info if the ray hits the sphere.
29    pub fn intersect_sphere(
30        &self,
31        center: V,
32        radius: V::Scalar,
33    ) -> Option<(V::Scalar, CollisionInfo<V>)> {
34        let offset = self.origin - center;
35        let direction_squared = self.direction.magnitude2();
36        let half_b = self.direction.dot(&offset);
37        let c = offset.magnitude2() - radius * radius;
38        let discriminant = half_b * half_b - direction_squared * c;
39
40        if discriminant < V::Scalar::zero() {
41            return None;
42        }
43
44        let sqrt_discriminant = discriminant.sqrt();
45        let mut parameter = (-half_b - sqrt_discriminant) / direction_squared;
46        if parameter < V::Scalar::zero() {
47            parameter = (-half_b + sqrt_discriminant) / direction_squared;
48            if parameter < V::Scalar::zero() {
49                return None;
50            }
51        }
52
53        let hit_point = self.origin + self.direction * parameter;
54        let normal = (hit_point - center) / radius;
55        let surface_point = center + normal * radius;
56
57        Some((
58            parameter,
59            CollisionInfo {
60                self_contact: hit_point,
61                other_contact: surface_point,
62                vector: self.direction * parameter,
63            },
64        ))
65    }
66}