box3d_rust/distance/types.rs
1// Distance-group types from include/box3d/types.h (query group).
2// SPDX-FileCopyrightText: 2026 Erin Catto
3// SPDX-License-Identifier: MIT
4
5use crate::constants::MAX_SHAPE_CAST_POINTS;
6use crate::core::NULL_INDEX;
7use crate::math_functions::{Quat, Transform, Vec3, QUAT_IDENTITY, VEC3_ZERO};
8
9/// A shape proxy is used by the GJK algorithm. It can represent a convex shape.
10///
11/// Unlike C's `b3ShapeProxy` (which holds a `const b3Vec3*` pointer), this owns
12/// a fixed-size point buffer so the proxy is self-contained and `Copy`.
13/// (b3ShapeProxy)
14#[derive(Debug, Clone, Copy, PartialEq)]
15pub struct ShapeProxy {
16 /// The point cloud.
17 pub points: [Vec3; MAX_SHAPE_CAST_POINTS],
18 /// The number of points. Do not exceed [`MAX_SHAPE_CAST_POINTS`].
19 pub count: i32,
20 /// The external radius of the point cloud.
21 pub radius: f32,
22}
23
24impl Default for ShapeProxy {
25 fn default() -> Self {
26 ShapeProxy {
27 points: [VEC3_ZERO; MAX_SHAPE_CAST_POINTS],
28 count: 0,
29 radius: 0.0,
30 }
31 }
32}
33
34/// Used to warm start the GJK simplex. If you call this function multiple times
35/// with nearby transforms this might improve performance. Otherwise you can
36/// zero initialize this. The distance cache must be initialized to zero on the
37/// first call. (b3SimplexCache)
38#[derive(Debug, Clone, Copy, PartialEq, Default)]
39pub struct SimplexCache {
40 /// Value used to compare length, area, volume of two simplexes.
41 pub metric: f32,
42 /// The number of stored simplex points
43 pub count: u16,
44 /// The cached simplex indices on shape A
45 pub index_a: [u8; 4],
46 /// The cached simplex indices on shape B
47 pub index_b: [u8; 4],
48}
49
50/// Input parameters for [`shape_cast`](crate::distance::shape_cast).
51/// (b3ShapeCastPairInput)
52#[derive(Debug, Clone, Copy, PartialEq)]
53pub struct ShapeCastPairInput {
54 /// The proxy for shape A
55 pub proxy_a: ShapeProxy,
56 /// The proxy for shape B
57 pub proxy_b: ShapeProxy,
58 /// Transform of shape B in shape A's frame, the relative pose B in A
59 pub transform: Transform,
60 /// The translation of shape B, in A's frame
61 pub translation_b: Vec3,
62 /// The fraction of the translation to consider, typically 1
63 pub max_fraction: f32,
64 /// Allows shapes with a radius to move slightly closer if already touching
65 pub can_encroach: bool,
66}
67
68/// Input for [`shape_distance`](crate::distance::shape_distance).
69/// (b3DistanceInput)
70#[derive(Debug, Clone, Copy, PartialEq)]
71pub struct DistanceInput {
72 /// The proxy for shape A
73 pub proxy_a: ShapeProxy,
74 /// The proxy for shape B
75 pub proxy_b: ShapeProxy,
76 /// Transform of shape B in shape A's frame, the relative pose B in A
77 /// (`inv_mul_transforms(world_a, world_b)`). The query is origin
78 /// independent and runs in frame A.
79 pub transform: Transform,
80 /// Should the proxy radius be considered?
81 pub use_radii: bool,
82}
83
84/// Output for [`shape_distance`](crate::distance::shape_distance).
85/// (b3DistanceOutput)
86#[derive(Debug, Clone, Copy, PartialEq, Default)]
87pub struct DistanceOutput {
88 /// Closest point on shape A, in shape A's frame
89 pub point_a: Vec3,
90 /// Closest point on shape B, in shape A's frame
91 pub point_b: Vec3,
92 /// A to B normal in shape A's frame. Invalid if distance is zero.
93 pub normal: Vec3,
94 /// The final distance, zero if overlapped
95 pub distance: f32,
96 /// Number of GJK iterations used
97 pub iterations: i32,
98 /// The number of simplexes stored in the simplex array
99 pub simplex_count: i32,
100}
101
102/// Simplex vertex for debugging the GJK algorithm. (b3SimplexVertex)
103#[derive(Debug, Clone, Copy, PartialEq, Default)]
104pub struct SimplexVertex {
105 /// support point in proxy A
106 pub w_a: Vec3,
107 /// support point in proxy B
108 pub w_b: Vec3,
109 /// w_b - w_a
110 pub w: Vec3,
111 /// barycentric coordinates
112 pub a: f32,
113 /// w_a index
114 pub index_a: i32,
115 /// w_b index
116 pub index_b: i32,
117}
118
119/// Simplex from the GJK algorithm. (b3Simplex)
120#[derive(Debug, Clone, Copy, PartialEq, Default)]
121pub struct Simplex {
122 /// vertices
123 pub vertices: [SimplexVertex; 4],
124 /// number of valid vertices
125 pub count: i32,
126}
127
128/// Low level ray cast or shape-cast output data. (b3CastOutput)
129#[derive(Debug, Clone, Copy, PartialEq)]
130pub struct CastOutput {
131 /// The surface normal at the hit point.
132 pub normal: Vec3,
133 /// The surface hit point.
134 pub point: Vec3,
135 /// The fraction of the input translation at collision.
136 pub fraction: f32,
137 /// The number of iterations used.
138 pub iterations: i32,
139 /// The index of the mesh or height field triangle hit.
140 pub triangle_index: i32,
141 /// The index of the compound child shape.
142 pub child_index: i32,
143 /// The material index. May be -1 for null.
144 pub material_index: i32,
145 /// Did the cast hit?
146 pub hit: bool,
147}
148
149impl Default for CastOutput {
150 fn default() -> Self {
151 CastOutput {
152 normal: VEC3_ZERO,
153 point: VEC3_ZERO,
154 fraction: 0.0,
155 iterations: 0,
156 triangle_index: NULL_INDEX,
157 child_index: 0,
158 material_index: 0,
159 hit: false,
160 }
161 }
162}
163
164/// This describes the motion of a body/shape for TOI computation. Shapes are
165/// defined with respect to the body origin, which may not coincide with the
166/// center of mass. However, to support dynamics we must interpolate the center
167/// of mass position. (b3Sweep)
168#[derive(Debug, Clone, Copy, PartialEq)]
169pub struct Sweep {
170 /// Local center of mass position
171 pub local_center: Vec3,
172 /// Starting center of mass world position
173 pub c1: Vec3,
174 /// Ending center of mass world position
175 pub c2: Vec3,
176 /// Starting world rotation
177 pub q1: Quat,
178 /// Ending world rotation
179 pub q2: Quat,
180}
181
182impl Default for Sweep {
183 fn default() -> Self {
184 Sweep {
185 local_center: VEC3_ZERO,
186 c1: VEC3_ZERO,
187 c2: VEC3_ZERO,
188 q1: QUAT_IDENTITY,
189 q2: QUAT_IDENTITY,
190 }
191 }
192}
193
194/// Time of impact input. (b3TOIInput)
195#[derive(Debug, Clone, Copy, PartialEq)]
196pub struct ToiInput {
197 /// The proxy for shape A
198 pub proxy_a: ShapeProxy,
199 /// The proxy for shape B
200 pub proxy_b: ShapeProxy,
201 /// The movement of shape A
202 pub sweep_a: Sweep,
203 /// The movement of shape B
204 pub sweep_b: Sweep,
205 /// Defines the sweep interval [0, max_fraction]
206 pub max_fraction: f32,
207}
208
209/// Describes the TOI output. (b3TOIState)
210#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
211pub enum ToiState {
212 #[default]
213 Unknown,
214 Failed,
215 Overlapped,
216 Hit,
217 Separated,
218}
219
220/// Time of impact output. (b3TOIOutput)
221#[derive(Debug, Clone, Copy, PartialEq, Default)]
222pub struct ToiOutput {
223 /// The type of result
224 pub state: ToiState,
225 /// The hit point
226 pub point: Vec3,
227 /// The hit normal
228 pub normal: Vec3,
229 /// The sweep time of the collision
230 pub fraction: f32,
231 /// The final distance
232 pub distance: f32,
233 /// Number of outer iterations
234 pub distance_iterations: i32,
235 /// Total number of push back iterations
236 pub push_back_iterations: i32,
237 /// Total number of root iterations
238 pub root_iterations: i32,
239 /// Indicates that the time of impact detected initial overlap and used a
240 /// fallback sphere as a last ditch effort to prevent tunneling.
241 /// (Present in the C type; never set by `b3TimeOfImpact` in the pinned source.)
242 pub used_fallback: bool,
243}