ncollide3d/query/point/
point_aabb.rs
1use crate::bounding_volume::AABB;
2use crate::math::{Isometry, Point, Vector, DIM};
3use crate::num::Zero;
4use crate::query::{PointProjection, PointQuery};
5use crate::shape::FeatureId;
6use na::{self, RealField};
7
8impl<N: RealField + Copy> AABB<N> {
9 fn local_point_projection(
10 &self,
11 m: &Isometry<N>,
12 pt: &Point<N>,
13 solid: bool,
14 ) -> (bool, Point<N>, Vector<N>) {
15 let ls_pt = m.inverse_transform_point(pt);
16 let mins_pt = self.mins - ls_pt;
17 let pt_maxs = ls_pt - self.maxs;
18 let shift = mins_pt.sup(&na::zero()) - pt_maxs.sup(&na::zero());
19
20 let inside = shift.is_zero();
21
22 if !inside {
23 (false, ls_pt + shift, shift)
24 } else if solid {
25 (true, ls_pt, shift)
26 } else {
27 let _max: N = N::max_value().unwrap();
28 let mut best = -_max;
29 let mut is_mins = false;
30 let mut best_id = 0;
31
32 for i in 0..DIM {
33 let mins_pt_i = mins_pt[i];
34 let pt_maxs_i = pt_maxs[i];
35
36 if mins_pt_i < pt_maxs_i {
37 if pt_maxs[i] > best {
38 best_id = i;
39 is_mins = false;
40 best = pt_maxs_i
41 }
42 } else if mins_pt_i > best {
43 best_id = i;
44 is_mins = true;
45 best = mins_pt_i
46 }
47 }
48
49 let mut shift: Vector<N> = na::zero();
50
51 if is_mins {
52 shift[best_id] = best;
53 } else {
54 shift[best_id] = -best;
55 }
56
57 (inside, ls_pt + shift, shift)
58 }
59 }
60}
61
62impl<N: RealField + Copy> PointQuery<N> for AABB<N> {
63 #[inline]
64 fn project_point(&self, m: &Isometry<N>, pt: &Point<N>, solid: bool) -> PointProjection<N> {
65 let (inside, ls_pt, _) = self.local_point_projection(m, pt, solid);
66 PointProjection::new(inside, m * ls_pt)
67 }
68
69 #[allow(unused_assignments)] #[allow(unused_variables)] #[inline]
72 fn project_point_with_feature(
73 &self,
74 m: &Isometry<N>,
75 pt: &Point<N>,
76 ) -> (PointProjection<N>, FeatureId) {
77 let (inside, ls_pt, shift) = self.local_point_projection(m, pt, false);
78 let proj = PointProjection::new(inside, m * ls_pt);
79 let mut nzero_shifts = 0;
80 let mut last_zero_shift = 0;
81 let mut last_not_zero_shift = 0;
82
83 for i in 0..DIM {
84 if shift[i].is_zero() {
85 nzero_shifts += 1;
86 last_zero_shift = i;
87 } else {
88 last_not_zero_shift = i;
89 }
90 }
91
92 if nzero_shifts == DIM {
93 for i in 0..DIM {
94 if ls_pt[i] > self.maxs[i] - N::default_epsilon() {
95 return (proj, FeatureId::Face(i));
96 }
97 if ls_pt[i] <= self.mins[i] + N::default_epsilon() {
98 return (proj, FeatureId::Face(i + DIM));
99 }
100 }
101
102 (proj, FeatureId::Unknown)
103 } else if nzero_shifts == DIM - 1 {
104 if ls_pt[last_not_zero_shift] < self.center()[last_not_zero_shift] {
106 (proj, FeatureId::Face(last_not_zero_shift + DIM))
107 } else {
108 (proj, FeatureId::Face(last_not_zero_shift))
109 }
110 } else {
111 let mut id = 0;
113 let center = self.center();
114
115 for i in 0..DIM {
116 if ls_pt[i] < center[i] {
117 id |= 1 << i;
118 }
119 }
120
121 #[cfg(feature = "dim3")]
122 {
123 if nzero_shifts == 0 {
124 (proj, FeatureId::Vertex(id))
125 } else {
126 (proj, FeatureId::Edge((id << 2) | last_zero_shift))
127 }
128 }
129
130 #[cfg(feature = "dim2")]
131 {
132 (proj, FeatureId::Vertex(id))
133 }
134 }
135 }
136
137 #[inline]
138 fn distance_to_point(&self, m: &Isometry<N>, pt: &Point<N>, solid: bool) -> N {
139 let ls_pt = m.inverse_transform_point(pt);
140 let mins_pt = self.mins - ls_pt;
141 let pt_maxs = ls_pt - self.maxs;
142 let shift = mins_pt.sup(&pt_maxs).sup(&na::zero());
143
144 if solid || !shift.is_zero() {
145 shift.norm()
146 } else {
147 -na::distance(pt, &self.project_point(m, pt, solid).point)
149 }
150 }
151
152 #[inline]
153 fn contains_point(&self, m: &Isometry<N>, pt: &Point<N>) -> bool {
154 let ls_pt = m.inverse_transform_point(pt);
155 self.contains_local_point(&ls_pt)
156 }
157}