Skip to main content

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}