parry2d/query/ray/
ray_aabb.rs1use core::mem;
2
3use crate::bounding_volume::Aabb;
4use crate::math::{Real, Vector, DIM};
5use crate::query::{Ray, RayCast, RayIntersection};
6use crate::shape::FeatureId;
7use num::Zero;
8
9impl RayCast for Aabb {
10 fn cast_local_ray(&self, ray: &Ray, max_time_of_impact: Real, solid: bool) -> Option<Real> {
11 let mut tmin: Real = 0.0;
12 let mut tmax: Real = max_time_of_impact;
13
14 for i in 0usize..DIM {
15 if ray.dir[i].is_zero() {
16 if ray.origin[i] < self.mins[i] || ray.origin[i] > self.maxs[i] {
17 return None;
18 }
19 } else {
20 let denom = 1.0 / ray.dir[i];
21 let mut inter_with_near_halfspace = (self.mins[i] - ray.origin[i]) * denom;
22 let mut inter_with_far_halfspace = (self.maxs[i] - ray.origin[i]) * denom;
23
24 if inter_with_near_halfspace > inter_with_far_halfspace {
25 mem::swap(
26 &mut inter_with_near_halfspace,
27 &mut inter_with_far_halfspace,
28 )
29 }
30
31 tmin = tmin.max(inter_with_near_halfspace);
32 tmax = tmax.min(inter_with_far_halfspace);
33
34 if tmin > tmax {
35 return None;
38 }
39 }
40 }
41
42 if tmin.is_zero() && !solid {
43 Some(tmax)
44 } else {
45 Some(tmin)
46 }
47 }
48
49 #[inline]
50 fn cast_local_ray_and_get_normal(
51 &self,
52 ray: &Ray,
53 max_time_of_impact: Real,
54 solid: bool,
55 ) -> Option<RayIntersection> {
56 ray_aabb(self, ray, max_time_of_impact, solid).map(|(t, n, i)| {
57 let feature = if i < 0 {
58 FeatureId::Face((-i) as u32 - 1 + 3)
59 } else {
60 FeatureId::Face(i as u32 - 1)
61 };
62
63 RayIntersection::new(t, n, feature)
64 })
65 }
66}
67
68fn ray_aabb(
69 aabb: &Aabb,
70 ray: &Ray,
71 max_time_of_impact: Real,
72 solid: bool,
73) -> Option<(Real, Vector, isize)> {
74 use crate::query::clip;
75 clip::clip_aabb_line(aabb, ray.origin, ray.dir).and_then(|(near, far)| {
76 if near.0 < 0.0 {
77 if solid {
78 Some((0.0, Vector::ZERO, far.2))
79 } else if far.0 <= max_time_of_impact {
80 Some(far)
81 } else {
82 None
83 }
84 } else if near.0 <= max_time_of_impact {
85 Some(near)
86 } else {
87 None
88 }
89 })
90}