parry3d/query/point/
point_aabb.rs1use crate::bounding_volume::Aabb;
2use crate::math::{Real, Vector, DIM};
3use crate::num::{Bounded, Zero};
4use crate::query::{PointProjection, PointQuery};
5use crate::shape::FeatureId;
6
7impl Aabb {
8 fn do_project_local_point(&self, pt: Vector, solid: bool) -> (bool, Vector, Vector) {
9 let mins_pt = self.mins - pt;
10 let pt_maxs = pt - self.maxs;
11 let shift = mins_pt.max(Vector::ZERO) - pt_maxs.max(Vector::ZERO);
12
13 let inside = shift == Vector::ZERO;
14
15 if !inside {
16 (false, pt + shift, shift)
17 } else if solid {
18 (true, pt, shift)
19 } else {
20 let _max: Real = Bounded::max_value();
21 let mut best = -_max;
22 let mut is_mins = false;
23 let mut best_id = 0;
24
25 for i in 0..DIM {
26 let mins_pt_i = mins_pt[i];
27 let pt_maxs_i = pt_maxs[i];
28
29 if mins_pt_i < pt_maxs_i {
30 if pt_maxs[i] > best {
31 best_id = i;
32 is_mins = false;
33 best = pt_maxs_i
34 }
35 } else if mins_pt_i > best {
36 best_id = i;
37 is_mins = true;
38 best = mins_pt_i
39 }
40 }
41
42 let mut shift: Vector = Vector::ZERO;
43
44 if is_mins {
45 shift[best_id] = best;
46 } else {
47 shift[best_id] = -best;
48 }
49
50 (inside, pt + shift, shift)
51 }
52 }
53}
54
55impl PointQuery for Aabb {
56 #[inline]
57 fn project_local_point(&self, pt: Vector, solid: bool) -> PointProjection {
58 let (inside, ls_pt, _) = self.do_project_local_point(pt, solid);
59 PointProjection::new(inside, ls_pt)
60 }
61
62 #[allow(unused_assignments)] #[allow(unused_variables)] #[inline]
65 fn project_local_point_and_get_feature(&self, pt: Vector) -> (PointProjection, FeatureId) {
66 let (inside, ls_pt, shift) = self.do_project_local_point(pt, false);
67 let proj = PointProjection::new(inside, ls_pt);
68 let mut nzero_shifts = 0;
69 let mut last_zero_shift = 0;
70 let mut last_not_zero_shift = 0;
71
72 for i in 0..DIM {
73 if shift[i].is_zero() {
74 nzero_shifts += 1;
75 last_zero_shift = i;
76 } else {
77 last_not_zero_shift = i;
78 }
79 }
80
81 if nzero_shifts == DIM {
82 for i in 0..DIM {
83 if ls_pt[i] > self.maxs[i] - crate::math::DEFAULT_EPSILON {
84 return (proj, FeatureId::Face(i as u32));
85 }
86 if ls_pt[i] <= self.mins[i] + crate::math::DEFAULT_EPSILON {
87 return (proj, FeatureId::Face((i + DIM) as u32));
88 }
89 }
90
91 (proj, FeatureId::Unknown)
92 } else if nzero_shifts == DIM - 1 {
93 if ls_pt[last_not_zero_shift] < self.center()[last_not_zero_shift] {
95 (proj, FeatureId::Face((last_not_zero_shift + DIM) as u32))
96 } else {
97 (proj, FeatureId::Face(last_not_zero_shift as u32))
98 }
99 } else {
100 let mut id = 0;
102 let center = self.center();
103
104 for i in 0..DIM {
105 if ls_pt[i] < center[i] {
106 id |= 1 << i;
107 }
108 }
109
110 #[cfg(feature = "dim3")]
111 {
112 if nzero_shifts == 0 {
113 (proj, FeatureId::Vertex(id))
114 } else {
115 (proj, FeatureId::Edge((id << 2) | (last_zero_shift as u32)))
116 }
117 }
118
119 #[cfg(feature = "dim2")]
120 {
121 (proj, FeatureId::Vertex(id))
122 }
123 }
124 }
125
126 #[inline]
127 fn distance_to_local_point(&self, pt: Vector, solid: bool) -> Real {
128 let mins_pt = self.mins - pt;
129 let pt_maxs = pt - self.maxs;
130 let shift = mins_pt.max(pt_maxs).max(Vector::ZERO);
131
132 if solid || shift != Vector::ZERO {
133 shift.length()
134 } else {
135 -pt.distance(self.project_local_point(pt, solid).point)
137 }
138 }
139}