1use super::simplex::{
6 compute_witness_points, get_metric, solve_simplex2, solve_simplex3, solve_simplex4, write_cache,
7};
8use super::types::{DistanceInput, DistanceOutput, ShapeProxy, Simplex, SimplexCache};
9use crate::math_functions::{
10 add, blend2, blend3, cross, distance, dot, is_normalized, length_squared,
11 make_matrix_from_quat, max_float, mul_mv, mul_sv, neg, normalize, sub, transpose, Vec3,
12 VEC3_ZERO,
13};
14
15const MAX_SIMPLEX_VERTICES: i32 = 4;
16const MAX_GJK_ITERATIONS: i32 = 32;
17
18pub fn get_proxy_support(proxy: &ShapeProxy, axis: Vec3) -> i32 {
25 let count = proxy.count;
26 debug_assert!(count > 0);
27
28 let origin = proxy.points[0];
30 let mut max_index = 0;
31 let mut max_projection = 0.0;
32
33 for index in 1..count {
34 let projection = dot(axis, sub(proxy.points[index as usize], origin));
36 if projection > max_projection {
37 max_index = index;
38 max_projection = projection;
39 }
40 }
41
42 max_index
43}
44
45pub fn get_point_support(points: &[Vec3], axis: Vec3) -> i32 {
47 let count = points.len() as i32;
48 debug_assert!(count > 0);
49
50 let origin = points[0];
52 let mut max_index = 0;
53 let mut max_projection = 0.0;
54
55 for index in 1..count {
56 let projection = dot(axis, sub(points[index as usize], origin));
58 if projection > max_projection {
59 max_index = index;
60 max_projection = projection;
61 }
62 }
63
64 max_index
65}
66
67pub fn shape_distance(
73 input: &DistanceInput,
74 cache: &mut SimplexCache,
75 mut simplexes: Option<&mut [Simplex]>,
76) -> DistanceOutput {
77 let xf = input.transform;
79
80 let m = make_matrix_from_quat(xf.q);
82 let mt = transpose(m);
83
84 let proxy_a = &input.proxy_a;
85 let proxy_b = &input.proxy_b;
86
87 debug_assert!(cache.count as i32 <= MAX_SIMPLEX_VERTICES);
89
90 let mut simplex = Simplex::default();
91
92 simplex.count = cache.count as i32;
93 for i in 0..cache.count as usize {
94 let index1 = cache.index_a[i] as i32;
95 let index2 = cache.index_b[i] as i32;
96
97 debug_assert!(0 <= index1 && index1 < proxy_a.count);
98 debug_assert!(0 <= index2 && index2 < proxy_b.count);
99
100 let vertex1 = proxy_a.points[index1 as usize];
101 let vertex2 = add(mul_mv(m, proxy_b.points[index2 as usize]), xf.p);
102
103 simplex.vertices[i].index_a = index1;
104 simplex.vertices[i].index_b = index2;
105 simplex.vertices[i].w_a = vertex1;
106 simplex.vertices[i].w_b = vertex2;
107 simplex.vertices[i].w = sub(vertex2, vertex1);
108 simplex.vertices[i].a = 0.0;
109 }
110
111 if simplex.count > 0 {
114 let metric1 = cache.metric;
115 let metric2 = get_metric(&simplex);
116
117 if 2.0 * metric1 < metric2 || metric2 < 0.5 * metric1 || metric2 < f32::EPSILON {
119 simplex.count = 0;
121 }
122 }
123
124 if simplex.count == 0 {
126 let vertex1 = proxy_a.points[0];
127 let vertex2 = add(mul_mv(m, proxy_b.points[0]), xf.p);
128
129 simplex.count = 1;
130 simplex.vertices[0].index_a = 0;
131 simplex.vertices[0].index_b = 0;
132 simplex.vertices[0].w_a = vertex1;
133 simplex.vertices[0].w_b = vertex2;
134 simplex.vertices[0].w = sub(vertex2, vertex1);
135 simplex.vertices[0].a = 0.0;
136 }
137
138 let mut backup = Simplex::default();
139
140 let mut simplex_index = 0usize;
141 if let Some(buffer) = simplexes.as_mut() {
142 if simplex_index < buffer.len() {
143 buffer[simplex_index] = simplex;
144 simplex_index += 1;
145 }
146 }
147
148 let mut distance_output = DistanceOutput::default();
149
150 let mut distance_sq = f32::MAX;
152
153 let mut normal = VEC3_ZERO;
154
155 let mut iteration = 0i32;
157 while iteration < MAX_GJK_ITERATIONS {
158 let solved = match simplex.count {
160 1 => {
161 simplex.vertices[0].a = 1.0;
162 true
163 }
164 2 => solve_simplex2(&mut simplex),
165 3 => solve_simplex3(&mut simplex),
166 4 => solve_simplex4(&mut simplex),
167 _ => {
168 debug_assert!(false, "Should never get here!");
169 false
170 }
171 };
172
173 if !solved {
174 debug_assert!(backup.count != 0);
176 simplex = backup;
177 break;
178 }
179
180 if let Some(buffer) = simplexes.as_mut() {
181 if simplex_index < buffer.len() {
182 buffer[simplex_index] = simplex;
183 simplex_index += 1;
184 distance_output.iterations = iteration;
185 distance_output.simplex_count = simplex_index as i32;
186 }
187 }
188
189 if simplex.count == MAX_SIMPLEX_VERTICES {
190 let (local_point_a, local_point_b) = compute_witness_points(&simplex);
192 distance_output.point_a = local_point_a;
193 distance_output.point_b = local_point_b;
194 return distance_output;
195 }
196
197 let old_distance_sq = distance_sq;
199
200 let closest_point = match simplex.count {
202 1 => simplex.vertices[0].w,
203 2 => blend2(
204 simplex.vertices[0].a,
205 simplex.vertices[0].w,
206 simplex.vertices[1].a,
207 simplex.vertices[1].w,
208 ),
209 3 => blend3(
210 simplex.vertices[0].a,
211 simplex.vertices[0].w,
212 simplex.vertices[1].a,
213 simplex.vertices[1].w,
214 simplex.vertices[2].a,
215 simplex.vertices[2].w,
216 ),
217 4 => add(
218 blend2(
219 simplex.vertices[0].a,
220 simplex.vertices[0].w,
221 simplex.vertices[1].a,
222 simplex.vertices[1].w,
223 ),
224 blend2(
225 simplex.vertices[2].a,
226 simplex.vertices[2].w,
227 simplex.vertices[3].a,
228 simplex.vertices[3].w,
229 ),
230 ),
231 _ => {
232 debug_assert!(false, "Should never get here!");
233 VEC3_ZERO
234 }
235 };
236
237 distance_sq = dot(closest_point, closest_point);
238
239 if distance_sq >= old_distance_sq {
240 debug_assert!(backup.count != 0);
242 simplex = backup;
243 break;
244 }
245
246 let search_direction = match simplex.count {
248 1 => {
249 neg(simplex.vertices[0].w)
251 }
252 2 => {
253 let a = simplex.vertices[0].w;
255 let b = simplex.vertices[1].w;
256 let ab = sub(b, a);
257 cross(cross(ab, neg(a)), ab)
258 }
259 3 => {
260 let a = simplex.vertices[0].w;
262 let b = simplex.vertices[1].w;
263 let c = simplex.vertices[2].w;
264 let ab = sub(b, a);
265 let ac = sub(c, a);
266 let n = cross(ab, ac);
267 if dot(n, a) < 0.0 {
268 n
269 } else {
270 neg(n)
271 }
272 }
273 _ => {
274 debug_assert!(false, "Should never get here!");
275 VEC3_ZERO
276 }
277 };
278
279 if length_squared(search_direction) < 1000.0 * f32::MIN_POSITIVE {
280 let (local_point_a, local_point_b) = compute_witness_points(&simplex);
283 distance_output.point_a = local_point_a;
284 distance_output.point_b = local_point_b;
285 debug_assert!(distance(local_point_a, local_point_b) < f32::EPSILON);
286 return distance_output;
287 }
288
289 normal = neg(search_direction);
290
291 let search_direction1 = search_direction;
293 let index_a = get_proxy_support(&input.proxy_a, neg(search_direction1));
294 let support_a = input.proxy_a.points[index_a as usize];
295 let search_direction2 = mul_mv(mt, search_direction);
296 let index_b = get_proxy_support(&input.proxy_b, search_direction2);
297 let support_b = add(mul_mv(m, input.proxy_b.points[index_b as usize]), xf.p);
298
299 backup = simplex;
301
302 let mut duplicate = false;
304 for i in 0..simplex.count as usize {
305 if simplex.vertices[i].index_a == index_a && simplex.vertices[i].index_b == index_b {
306 duplicate = true;
307 break;
308 }
309 }
310
311 if duplicate {
312 break;
313 }
314
315 let count = simplex.count as usize;
316 simplex.vertices[count].index_a = index_a;
317 simplex.vertices[count].index_b = index_b;
318 simplex.vertices[count].w_a = support_a;
319 simplex.vertices[count].w_b = support_b;
320 simplex.vertices[count].w = sub(support_b, support_a);
321 simplex.count += 1;
322
323 iteration += 1;
324 }
325
326 normal = normalize(normal);
327 if !is_normalized(normal) {
328 return distance_output;
330 }
331
332 let (local_point_a, local_point_b) = compute_witness_points(&simplex);
334 write_cache(cache, &simplex);
335
336 distance_output.point_a = local_point_a;
338 distance_output.point_b = local_point_b;
339 distance_output.distance = distance(local_point_a, local_point_b);
340 distance_output.normal = normal;
341 distance_output.iterations = iteration;
342 distance_output.simplex_count = simplex_index as i32;
343
344 if input.use_radii {
346 let r_a = input.proxy_a.radius;
347 let r_b = input.proxy_b.radius;
348 distance_output.distance = max_float(0.0, distance_output.distance - r_a - r_b);
349
350 distance_output.point_a = add(distance_output.point_a, mul_sv(r_a, normal));
352 distance_output.point_b = sub(distance_output.point_b, mul_sv(r_b, normal));
353 }
354
355 distance_output
356}