parry2d/query/ray/
ray_halfspace.rs

1use crate::math::{Real, Vector};
2use crate::query::{Ray, RayCast, RayIntersection};
3use crate::shape::{FeatureId, HalfSpace};
4
5/// Computes the time_of_impact of an unbounded line with a halfspace described by its center and normal.
6#[inline]
7pub fn line_toi_with_halfspace(
8    halfspace_center: Vector,
9    halfspace_normal: Vector,
10    line_origin: Vector,
11    line_dir: Vector,
12) -> Option<Real> {
13    let dpos = halfspace_center - line_origin;
14    let denom = halfspace_normal.dot(line_dir);
15
16    if relative_eq!(denom, 0.0) {
17        None
18    } else {
19        Some(halfspace_normal.dot(dpos) / denom)
20    }
21}
22
23/// Computes the time_of_impact of a ray with a halfspace described by its center and normal.
24#[inline]
25pub fn ray_toi_with_halfspace(center: Vector, normal: Vector, ray: &Ray) -> Option<Real> {
26    if let Some(t) = line_toi_with_halfspace(center, normal, ray.origin, ray.dir) {
27        if t >= 0.0 {
28            return Some(t);
29        }
30    }
31
32    None
33}
34
35impl RayCast for HalfSpace {
36    #[inline]
37    fn cast_local_ray_and_get_normal(
38        &self,
39        ray: &Ray,
40        max_time_of_impact: Real,
41        solid: bool,
42    ) -> Option<RayIntersection> {
43        let dpos = -ray.origin;
44
45        let dot_normal_dpos = self.normal.dot(dpos);
46
47        if solid && dot_normal_dpos > 0.0 {
48            // The ray is inside of the solid half-space.
49            return Some(RayIntersection::new(0.0, Vector::ZERO, FeatureId::Face(0)));
50        }
51
52        let t = dot_normal_dpos / self.normal.dot(ray.dir);
53
54        if t >= 0.0 && t <= max_time_of_impact {
55            let n = if dot_normal_dpos > 0.0 {
56                -self.normal
57            } else {
58                self.normal
59            };
60
61            Some(RayIntersection::new(t, n, FeatureId::Face(0)))
62        } else {
63            None
64        }
65    }
66}