1use crate::bounding_volume::Aabb;
2use crate::math::{Pose, Real, Vector};
3use crate::shape::{Shape, TypedShape};
4
5#[cfg(feature = "dim2")]
7pub const TOI_PROXY_INLINE_POINTS: usize = 4;
8#[cfg(feature = "dim3")]
10pub const TOI_PROXY_INLINE_POINTS: usize = 8;
11
12enum ProxyPoints<'a> {
13 Inline([Vector; TOI_PROXY_INLINE_POINTS], u8),
14 Borrowed(&'a [Vector]),
15}
16
17pub struct ToiProxy<'a> {
25 points: ProxyPoints<'a>,
26 pub radius: Real,
28}
29
30impl<'a> ToiProxy<'a> {
31 pub fn point(point: Vector, radius: Real) -> Self {
33 let mut buf = [Vector::ZERO; TOI_PROXY_INLINE_POINTS];
34 buf[0] = point;
35 Self {
36 points: ProxyPoints::Inline(buf, 1),
37 radius,
38 }
39 }
40
41 pub fn from_points(points: &'a [Vector], radius: Real) -> Self {
43 assert!(!points.is_empty());
44 Self {
45 points: ProxyPoints::Borrowed(points),
46 radius,
47 }
48 }
49
50 pub fn from_array<const N: usize>(points: [Vector; N], radius: Real) -> Self {
52 assert!(N > 0 && N <= TOI_PROXY_INLINE_POINTS);
53 let mut buf = [Vector::ZERO; TOI_PROXY_INLINE_POINTS];
54 buf[..N].copy_from_slice(&points);
55 Self {
56 points: ProxyPoints::Inline(buf, N as u8),
57 radius,
58 }
59 }
60
61 pub fn from_shape(shape: &'a dyn Shape) -> Option<Self> {
63 match shape.as_typed_shape() {
64 TypedShape::Ball(ball) => Some(Self::point(Vector::ZERO, ball.radius)),
65 TypedShape::Cuboid(cuboid) => {
66 Some(Self::from_cuboid_half_extents(cuboid.half_extents, 0.0))
67 }
68 TypedShape::RoundCuboid(round) => Some(Self::from_cuboid_half_extents(
69 round.inner_shape.half_extents,
70 round.border_radius,
71 )),
72 TypedShape::Capsule(capsule) => Some(Self::from_array(
73 [capsule.segment.a, capsule.segment.b],
74 capsule.radius,
75 )),
76 TypedShape::Segment(segment) => Some(Self::from_array([segment.a, segment.b], 0.0)),
77 TypedShape::Triangle(tri) => Some(Self::from_array([tri.a, tri.b, tri.c], 0.0)),
78 TypedShape::RoundTriangle(round) => {
79 let tri = &round.inner_shape;
80 Some(Self::from_array([tri.a, tri.b, tri.c], round.border_radius))
81 }
82 #[cfg(feature = "dim2")]
83 #[cfg(feature = "alloc")]
84 TypedShape::ConvexPolygon(poly) => Some(Self::from_points(poly.points(), 0.0)),
85 #[cfg(feature = "dim2")]
86 #[cfg(feature = "alloc")]
87 TypedShape::RoundConvexPolygon(round) => Some(Self::from_points(
88 round.inner_shape.points(),
89 round.border_radius,
90 )),
91 #[cfg(feature = "dim3")]
92 #[cfg(feature = "alloc")]
93 TypedShape::ConvexPolyhedron(poly) => Some(Self::from_points(poly.points(), 0.0)),
94 #[cfg(feature = "dim3")]
95 #[cfg(feature = "alloc")]
96 TypedShape::RoundConvexPolyhedron(round) => Some(Self::from_points(
97 round.inner_shape.points(),
98 round.border_radius,
99 )),
100 _ => None,
101 }
102 }
103
104 fn from_cuboid_half_extents(he: Vector, radius: Real) -> Self {
105 #[cfg(feature = "dim2")]
106 {
107 Self::from_array(
108 [
109 Vector::new(-he.x, -he.y),
110 Vector::new(he.x, -he.y),
111 Vector::new(he.x, he.y),
112 Vector::new(-he.x, he.y),
113 ],
114 radius,
115 )
116 }
117 #[cfg(feature = "dim3")]
118 {
119 Self::from_array(
120 [
121 Vector::new(-he.x, -he.y, -he.z),
122 Vector::new(he.x, -he.y, -he.z),
123 Vector::new(he.x, he.y, -he.z),
124 Vector::new(-he.x, he.y, -he.z),
125 Vector::new(-he.x, -he.y, he.z),
126 Vector::new(he.x, -he.y, he.z),
127 Vector::new(he.x, he.y, he.z),
128 Vector::new(-he.x, he.y, he.z),
129 ],
130 radius,
131 )
132 }
133 }
134
135 #[inline]
137 pub fn points(&self) -> &[Vector] {
138 match &self.points {
139 ProxyPoints::Inline(buf, len) => &buf[..*len as usize],
140 ProxyPoints::Borrowed(points) => points,
141 }
142 }
143
144 #[inline]
149 pub fn support(&self, direction: Vector) -> u32 {
150 let points = self.points();
151 let origin = points[0];
152 let mut best_index = 0;
153 let mut best_value = 0.0;
154 for (i, pt) in points.iter().enumerate().skip(1) {
155 let value = direction.dot(*pt - origin);
156 if value > best_value {
157 best_index = i;
158 best_value = value;
159 }
160 }
161 best_index as u32
162 }
163
164 pub fn compute_aabb(&self, pose: &Pose) -> Aabb {
166 let points = self.points();
167 let mut mins = pose.transform_point(points[0]);
168 let mut maxs = mins;
169 for pt in &points[1..] {
170 let p = pose.transform_point(*pt);
171 mins = mins.min(p);
172 maxs = maxs.max(p);
173 }
174 Aabb::new(
175 mins - Vector::splat(self.radius),
176 maxs + Vector::splat(self.radius),
177 )
178 }
179}