box2d_rust/distance/
mod.rs1mod cast;
21mod gjk;
22mod toi;
23mod types;
24
25pub use cast::shape_cast;
26pub use gjk::shape_distance;
27pub use toi::time_of_impact;
28pub use types::{
29 DistanceInput, DistanceOutput, SegmentDistanceResult, ShapeCastPairInput, ShapeProxy, Simplex,
30 SimplexCache, SimplexVertex, Sweep, ToiInput, ToiOutput, ToiState,
31};
32
33use crate::hull::MAX_POLYGON_VERTICES;
34use crate::math_functions::{
35 add, clamp_float, distance_squared, dot, min_int, mul_add, mul_sv, normalize_rot,
36 rotate_vector, sub, transform_point, Rot, Transform, Vec2,
37};
38
39pub fn get_sweep_transform(sweep: &Sweep, time: f32) -> Transform {
41 let mut xf = Transform {
43 p: add(mul_sv(1.0 - time, sweep.c1), mul_sv(time, sweep.c2)),
44 q: normalize_rot(Rot {
45 c: (1.0 - time) * sweep.q1.c + time * sweep.q2.c,
46 s: (1.0 - time) * sweep.q1.s + time * sweep.q2.s,
47 }),
48 };
49
50 xf.p = sub(xf.p, rotate_vector(xf.q, sweep.local_center));
52 xf
53}
54
55pub fn segment_distance(p1: Vec2, q1: Vec2, p2: Vec2, q2: Vec2) -> SegmentDistanceResult {
60 let mut result = SegmentDistanceResult::default();
61
62 let d1 = sub(q1, p1);
63 let d2 = sub(q2, p2);
64 let r = sub(p1, p2);
65 let dd1 = dot(d1, d1);
66 let dd2 = dot(d2, d2);
67 let rd1 = dot(r, d1);
68 let rd2 = dot(r, d2);
69
70 let eps_sqr = f32::EPSILON * f32::EPSILON;
71
72 if dd1 < eps_sqr || dd2 < eps_sqr {
73 if dd1 >= eps_sqr {
75 result.fraction1 = clamp_float(-rd1 / dd1, 0.0, 1.0);
77 result.fraction2 = 0.0;
78 } else if dd2 >= eps_sqr {
79 result.fraction1 = 0.0;
81 result.fraction2 = clamp_float(rd2 / dd2, 0.0, 1.0);
82 } else {
83 result.fraction1 = 0.0;
84 result.fraction2 = 0.0;
85 }
86 } else {
87 let d12 = dot(d1, d2);
89
90 let denominator = dd1 * dd2 - d12 * d12;
91
92 let mut f1 = 0.0;
94 if denominator != 0.0 {
95 f1 = clamp_float((d12 * rd2 - rd1 * dd2) / denominator, 0.0, 1.0);
97 }
98
99 let mut f2 = (d12 * f1 + rd2) / dd2;
101
102 if f2 < 0.0 {
104 f2 = 0.0;
105 f1 = clamp_float(-rd1 / dd1, 0.0, 1.0);
106 } else if f2 > 1.0 {
107 f2 = 1.0;
108 f1 = clamp_float((d12 - rd1) / dd1, 0.0, 1.0);
109 }
110
111 result.fraction1 = f1;
112 result.fraction2 = f2;
113 }
114
115 result.closest1 = mul_add(p1, result.fraction1, d1);
116 result.closest2 = mul_add(p2, result.fraction2, d2);
117 result.distance_squared = distance_squared(result.closest1, result.closest2);
118 result
119}
120
121pub fn make_proxy(points: &[Vec2], radius: f32) -> ShapeProxy {
124 let count = min_int(points.len() as i32, MAX_POLYGON_VERTICES as i32);
125 let mut proxy = ShapeProxy {
126 points: [Vec2::default(); MAX_POLYGON_VERTICES],
127 count,
128 radius,
129 };
130 proxy.points[..count as usize].copy_from_slice(&points[..count as usize]);
131 proxy
132}
133
134pub fn make_offset_proxy(
137 points: &[Vec2],
138 radius: f32,
139 position: Vec2,
140 rotation: Rot,
141) -> ShapeProxy {
142 let count = min_int(points.len() as i32, MAX_POLYGON_VERTICES as i32);
143 let transform = Transform {
144 p: position,
145 q: rotation,
146 };
147 let mut proxy = ShapeProxy {
148 points: [Vec2::default(); MAX_POLYGON_VERTICES],
149 count,
150 radius,
151 };
152 for (dst, src) in proxy.points[..count as usize]
153 .iter_mut()
154 .zip(&points[..count as usize])
155 {
156 *dst = transform_point(transform, *src);
157 }
158 proxy
159}