1use super::types::{DistanceInput, DistanceOutput, ShapeProxy, Simplex, SimplexCache};
6use crate::math_functions::{
7 add, cross, cross_sv, distance, dot, is_normalized, max_float, mul_add, mul_sub, neg,
8 normalize, sub, transform_point, Vec2, VEC2_ZERO,
9};
10
11pub(crate) fn weight2(a1: f32, w1: Vec2, a2: f32, w2: Vec2) -> Vec2 {
12 Vec2 {
13 x: a1 * w1.x + a2 * w2.x,
14 y: a1 * w1.y + a2 * w2.y,
15 }
16}
17
18fn weight3(a1: f32, w1: Vec2, a2: f32, w2: Vec2, a3: f32, w3: Vec2) -> Vec2 {
19 Vec2 {
20 x: a1 * w1.x + a2 * w2.x + a3 * w3.x,
21 y: a1 * w1.y + a2 * w2.y + a3 * w3.y,
22 }
23}
24
25pub(crate) fn find_support(proxy: &ShapeProxy, direction: Vec2) -> i32 {
26 let points = &proxy.points;
27 let count = proxy.count;
28
29 let mut best_index = 0;
30 let mut best_value = dot(points[0], direction);
31 for i in 1..count {
32 let value = dot(points[i as usize], direction);
33 if value > best_value {
34 best_index = i;
35 best_value = value;
36 }
37 }
38
39 best_index
40}
41
42fn make_simplex_from_cache(
43 cache: &SimplexCache,
44 proxy_a: &ShapeProxy,
45 proxy_b: &ShapeProxy,
46) -> Simplex {
47 debug_assert!(cache.count <= 3);
48 let mut s = Simplex {
49 count: cache.count as i32,
50 ..Default::default()
51 };
52
53 for i in 0..s.count {
55 let v = s.vertex_mut(i);
56 v.index_a = cache.index_a[i as usize] as i32;
57 v.index_b = cache.index_b[i as usize] as i32;
58 v.w_a = proxy_a.points[v.index_a as usize];
59 v.w_b = proxy_b.points[v.index_b as usize];
60 v.w = sub(v.w_a, v.w_b);
61
62 v.a = -1.0;
64 }
65
66 if s.count == 0 {
68 let v = s.vertex_mut(0);
69 v.index_a = 0;
70 v.index_b = 0;
71 v.w_a = proxy_a.points[0];
72 v.w_b = proxy_b.points[0];
73 v.w = sub(v.w_a, v.w_b);
74 v.a = 1.0;
75 s.count = 1;
76 }
77
78 s
79}
80
81fn make_simplex_cache(simplex: &Simplex) -> SimplexCache {
82 let mut cache = SimplexCache {
83 count: simplex.count as u16,
84 ..Default::default()
85 };
86 for i in 0..simplex.count {
87 cache.index_a[i as usize] = simplex.vertex(i).index_a as u8;
88 cache.index_b[i as usize] = simplex.vertex(i).index_b as u8;
89 }
90
91 cache
92}
93
94pub(crate) fn compute_witness_points(s: &Simplex) -> (Vec2, Vec2) {
95 match s.count {
96 1 => (s.v1.w_a, s.v1.w_b),
97
98 2 => (
99 weight2(s.v1.a, s.v1.w_a, s.v2.a, s.v2.w_a),
100 weight2(s.v1.a, s.v1.w_b, s.v2.a, s.v2.w_b),
101 ),
102
103 3 => {
104 let a = weight3(s.v1.a, s.v1.w_a, s.v2.a, s.v2.w_a, s.v3.a, s.v3.w_a);
105 (a, a)
108 }
109
110 _ => {
111 debug_assert!(false);
112 (VEC2_ZERO, VEC2_ZERO)
113 }
114 }
115}
116
117pub(crate) fn solve_simplex2(s: &mut Simplex) -> Vec2 {
143 let w1 = s.v1.w;
144 let w2 = s.v2.w;
145 let e12 = sub(w2, w1);
146
147 let d12_2 = -dot(w1, e12);
149 if d12_2 <= 0.0 {
150 s.v1.a = 1.0;
152 s.count = 1;
153 return neg(w1);
154 }
155
156 let d12_1 = dot(w2, e12);
158 if d12_1 <= 0.0 {
159 s.v2.a = 1.0;
161 s.count = 1;
162 s.v1 = s.v2;
163 return neg(w2);
164 }
165
166 let inv_d12 = 1.0 / (d12_1 + d12_2);
168 s.v1.a = d12_1 * inv_d12;
169 s.v2.a = d12_2 * inv_d12;
170 s.count = 2;
171 cross_sv(cross(add(w1, w2), e12), e12)
172}
173
174pub(crate) fn solve_simplex3(s: &mut Simplex) -> Vec2 {
175 let w1 = s.v1.w;
176 let w2 = s.v2.w;
177 let w3 = s.v3.w;
178
179 let e12 = sub(w2, w1);
184 let w1e12 = dot(w1, e12);
185 let w2e12 = dot(w2, e12);
186 let d12_1 = w2e12;
187 let d12_2 = -w1e12;
188
189 let e13 = sub(w3, w1);
194 let w1e13 = dot(w1, e13);
195 let w3e13 = dot(w3, e13);
196 let d13_1 = w3e13;
197 let d13_2 = -w1e13;
198
199 let e23 = sub(w3, w2);
204 let w2e23 = dot(w2, e23);
205 let w3e23 = dot(w3, e23);
206 let d23_1 = w3e23;
207 let d23_2 = -w2e23;
208
209 let n123 = cross(e12, e13);
211
212 let d123_1 = n123 * cross(w2, w3);
213 let d123_2 = n123 * cross(w3, w1);
214 let d123_3 = n123 * cross(w1, w2);
215
216 if d12_2 <= 0.0 && d13_2 <= 0.0 {
218 s.v1.a = 1.0;
219 s.count = 1;
220 return neg(w1);
221 }
222
223 if d12_1 > 0.0 && d12_2 > 0.0 && d123_3 <= 0.0 {
225 let inv_d12 = 1.0 / (d12_1 + d12_2);
226 s.v1.a = d12_1 * inv_d12;
227 s.v2.a = d12_2 * inv_d12;
228 s.count = 2;
229 return cross_sv(cross(add(w1, w2), e12), e12);
230 }
231
232 if d13_1 > 0.0 && d13_2 > 0.0 && d123_2 <= 0.0 {
234 let inv_d13 = 1.0 / (d13_1 + d13_2);
235 s.v1.a = d13_1 * inv_d13;
236 s.v3.a = d13_2 * inv_d13;
237 s.count = 2;
238 s.v2 = s.v3;
239 return cross_sv(cross(add(w1, w3), e13), e13);
240 }
241
242 if d12_1 <= 0.0 && d23_2 <= 0.0 {
244 s.v2.a = 1.0;
245 s.count = 1;
246 s.v1 = s.v2;
247 return neg(w2);
248 }
249
250 if d13_1 <= 0.0 && d23_1 <= 0.0 {
252 s.v3.a = 1.0;
253 s.count = 1;
254 s.v1 = s.v3;
255 return neg(w3);
256 }
257
258 if d23_1 > 0.0 && d23_2 > 0.0 && d123_1 <= 0.0 {
260 let inv_d23 = 1.0 / (d23_1 + d23_2);
261 s.v2.a = d23_1 * inv_d23;
262 s.v3.a = d23_2 * inv_d23;
263 s.count = 2;
264 s.v1 = s.v3;
265 return cross_sv(cross(add(w2, w3), e23), e23);
266 }
267
268 let inv_d123 = 1.0 / (d123_1 + d123_2 + d123_3);
270 s.v1.a = d123_1 * inv_d123;
271 s.v2.a = d123_2 * inv_d123;
272 s.v3.a = d123_3 * inv_d123;
273 s.count = 3;
274
275 VEC2_ZERO
277}
278
279pub fn shape_distance(
290 input: &DistanceInput,
291 cache: &mut SimplexCache,
292 mut simplexes: Option<&mut [Simplex]>,
293) -> DistanceOutput {
294 debug_assert!(input.proxy_a.count > 0 && input.proxy_b.count > 0);
295 debug_assert!(input.proxy_a.radius >= 0.0);
296 debug_assert!(input.proxy_b.radius >= 0.0);
297
298 let mut output = DistanceOutput::default();
299
300 let proxy_a = &input.proxy_a;
301
302 let mut local_proxy_b = ShapeProxy {
305 count: input.proxy_b.count,
306 radius: input.proxy_b.radius,
307 ..Default::default()
308 };
309 for i in 0..local_proxy_b.count as usize {
310 local_proxy_b.points[i] = transform_point(input.transform, input.proxy_b.points[i]);
311 }
312
313 let mut simplex = make_simplex_from_cache(cache, proxy_a, &local_proxy_b);
315
316 let mut simplex_index = 0;
317 if let Some(buffer) = simplexes.as_mut() {
318 if simplex_index < buffer.len() {
319 buffer[simplex_index] = simplex;
320 simplex_index += 1;
321 }
322 }
323
324 let mut non_unit_normal = VEC2_ZERO;
325
326 let mut save_a = [0i32; 3];
329 let mut save_b = [0i32; 3];
330
331 let max_iterations = 20;
333 let mut iteration = 0;
334 while iteration < max_iterations {
335 let save_count = simplex.count;
337 for i in 0..save_count {
338 save_a[i as usize] = simplex.vertex(i).index_a;
339 save_b[i as usize] = simplex.vertex(i).index_b;
340 }
341
342 let d = match simplex.count {
343 1 => neg(simplex.v1.w),
344 2 => solve_simplex2(&mut simplex),
345 3 => solve_simplex3(&mut simplex),
346 _ => {
347 debug_assert!(false);
348 VEC2_ZERO
349 }
350 };
351
352 if simplex.count == 3 {
354 let (local_point_a, local_point_b) = compute_witness_points(&simplex);
356 output.point_a = local_point_a;
357 output.point_b = local_point_b;
358 return output;
359 }
360
361 if let Some(buffer) = simplexes.as_mut() {
362 if simplex_index < buffer.len() {
363 buffer[simplex_index] = simplex;
364 simplex_index += 1;
365 }
366 }
367
368 if dot(d, d) < f32::EPSILON * f32::EPSILON {
370 let (local_point_a, local_point_b) = compute_witness_points(&simplex);
378 output.point_a = local_point_a;
379 output.point_b = local_point_b;
380 return output;
381 }
382
383 non_unit_normal = d;
385
386 let index_a = find_support(proxy_a, d);
389 let index_b = find_support(&local_proxy_b, neg(d));
390 let vertex = simplex.vertex_mut(simplex.count);
391 vertex.index_a = index_a;
392 vertex.w_a = proxy_a.points[index_a as usize];
393 vertex.index_b = index_b;
394 vertex.w_b = local_proxy_b.points[index_b as usize];
395 vertex.w = sub(vertex.w_a, vertex.w_b);
396
397 iteration += 1;
399
400 let mut duplicate = false;
402 for i in 0..save_count {
403 if index_a == save_a[i as usize] && index_b == save_b[i as usize] {
404 duplicate = true;
405 break;
406 }
407 }
408
409 if duplicate {
411 break;
412 }
413
414 simplex.count += 1;
416 }
417
418 if let Some(buffer) = simplexes.as_mut() {
419 if simplex_index < buffer.len() {
420 buffer[simplex_index] = simplex;
421 simplex_index += 1;
422 }
423 }
424
425 let normal = normalize(non_unit_normal);
427 debug_assert!(is_normalized(normal));
428
429 let (local_point_a, local_point_b) = compute_witness_points(&simplex);
430 output.normal = normal;
431 output.distance = distance(local_point_a, local_point_b);
432 output.point_a = local_point_a;
433 output.point_b = local_point_b;
434 output.iterations = iteration;
435 output.simplex_count = simplex_index as i32;
436
437 *cache = make_simplex_cache(&simplex);
439
440 if input.use_radii {
442 let radius_a = input.proxy_a.radius;
443 let radius_b = input.proxy_b.radius;
444 output.distance = max_float(0.0, output.distance - radius_a - radius_b);
445
446 output.point_a = mul_add(output.point_a, radius_a, normal);
449 output.point_b = mul_sub(output.point_b, radius_b, normal);
450 }
451
452 output
453}