box2d_rust/distance/
cast.rs1use super::gjk::shape_distance;
6use super::types::{DistanceInput, ShapeCastPairInput, SimplexCache};
7use crate::collision::CastOutput;
8use crate::constants::linear_slop;
9use crate::math_functions::{dot, is_normalized, lerp, max_float, mul_add};
10
11pub fn shape_cast(input: &ShapeCastPairInput) -> CastOutput {
18 let slop = linear_slop();
20 let total_radius = input.proxy_a.radius + input.proxy_b.radius;
21 let mut target = max_float(slop, total_radius - slop);
22 let tolerance = 0.25 * slop;
23
24 debug_assert!(target > tolerance);
25
26 let mut cache = SimplexCache::default();
28
29 let mut fraction = 0.0;
30
31 let mut distance_input = DistanceInput {
32 proxy_a: input.proxy_a,
33 proxy_b: input.proxy_b,
34 transform: input.transform,
38 use_radii: false,
39 };
40
41 let delta2 = input.translation_b;
42 let mut output = CastOutput::default();
43
44 let max_iterations = 20;
45
46 for iteration in 0..max_iterations {
47 output.iterations += 1;
48
49 let distance_output = shape_distance(&distance_input, &mut cache, None);
50
51 if distance_output.distance < target + tolerance {
52 if iteration == 0 {
53 if input.can_encroach && distance_output.distance > 2.0 * slop {
54 target = distance_output.distance - slop;
55 } else {
56 output.hit = true;
58
59 let c1 = mul_add(
61 distance_output.point_a,
62 input.proxy_a.radius,
63 distance_output.normal,
64 );
65 let c2 = mul_add(
66 distance_output.point_b,
67 -input.proxy_b.radius,
68 distance_output.normal,
69 );
70 output.point = lerp(c1, c2, 0.5);
71 return output;
72 }
73 } else {
74 debug_assert!(
76 distance_output.distance > 0.0 && is_normalized(distance_output.normal)
77 );
78 output.fraction = fraction;
79 output.point = mul_add(
80 distance_output.point_a,
81 input.proxy_a.radius,
82 distance_output.normal,
83 );
84 output.normal = distance_output.normal;
85 output.hit = true;
86 return output;
87 }
88 }
89
90 debug_assert!(distance_output.distance > 0.0);
91 debug_assert!(is_normalized(distance_output.normal));
92
93 let denominator = dot(delta2, distance_output.normal);
95 if denominator >= 0.0 {
96 return output;
98 }
99
100 fraction += (target - distance_output.distance) / denominator;
102 if fraction >= input.max_fraction {
103 return output;
105 }
106
107 distance_input.transform.p = mul_add(input.transform.p, fraction, delta2);
108 }
109
110 output
112}