box2d_rust/collision.rs
1// Port of box2d-cpp-reference/include/box2d/collision.h
2//
3// This module holds the collision data types, ported incrementally: each type
4// lands together with the first module that consumes it.
5//
6// SPDX-FileCopyrightText: 2022 Erin Catto
7// SPDX-License-Identifier: MIT
8
9use crate::distance::ShapeProxy;
10use crate::hull::MAX_POLYGON_VERTICES;
11use crate::math_functions::{Plane, Vec2, VEC2_ZERO};
12
13/// Low level ray cast input data. (b2RayCastInput)
14#[derive(Debug, Clone, Copy, PartialEq, Default)]
15pub struct RayCastInput {
16 /// Start point of the ray cast
17 pub origin: Vec2,
18 /// Translation of the ray cast
19 pub translation: Vec2,
20 /// The maximum fraction of the translation to consider, typically 1
21 pub max_fraction: f32,
22}
23
24/// Low level shape cast input in generic form. This allows casting an
25/// arbitrary point cloud wrapped with a radius. For example, a circle is a
26/// single point with a non-zero radius. A capsule is two points with a
27/// non-zero radius. A box is four points with a zero radius. (b2ShapeCastInput)
28#[derive(Debug, Clone, Copy, PartialEq, Default)]
29pub struct ShapeCastInput {
30 /// A generic shape
31 pub proxy: ShapeProxy,
32 /// The translation of the shape cast
33 pub translation: Vec2,
34 /// The maximum fraction of the translation to consider, typically 1
35 pub max_fraction: f32,
36 /// Allow shape cast to encroach when initially touching. This only works
37 /// if the radius is greater than zero.
38 pub can_encroach: bool,
39}
40
41/// Low level ray cast or shape cast output data. The hit point is in the local
42/// or relative frame of the input. Returns a zero fraction and normal in the
43/// case of initial overlap. (b2CastOutput)
44#[derive(Debug, Clone, Copy, PartialEq, Default)]
45pub struct CastOutput {
46 /// The surface normal at the hit point
47 pub normal: Vec2,
48 /// The surface hit point
49 pub point: Vec2,
50 /// The fraction of the input translation at collision
51 pub fraction: f32,
52 /// The number of iterations used
53 pub iterations: i32,
54 /// Did the cast hit?
55 pub hit: bool,
56}
57
58/// Ray cast or shape cast output with the hit point lifted back to a world
59/// position. In the C single-precision build this is an alias of b2CastOutput;
60/// the double-precision build widens `point` to b2Pos, which is what the
61/// unconditional `Pos` here does in both modes. (b2WorldCastOutput)
62#[derive(Debug, Clone, Copy, PartialEq, Default)]
63pub struct WorldCastOutput {
64 /// The surface normal at the hit point
65 pub normal: Vec2,
66 /// The surface hit point in world space
67 pub point: crate::math_functions::Pos,
68 /// The fraction of the input translation at collision
69 pub fraction: f32,
70 /// The number of iterations used
71 pub iterations: i32,
72 /// Did the cast hit?
73 pub hit: bool,
74}
75
76/// This holds the mass data computed for a shape. (b2MassData)
77#[derive(Debug, Clone, Copy, PartialEq, Default)]
78pub struct MassData {
79 /// The mass of the shape, usually in kilograms.
80 pub mass: f32,
81 /// The position of the shape's centroid relative to the shape's origin.
82 pub center: Vec2,
83 /// The rotational inertia of the shape about the shape center.
84 pub rotational_inertia: f32,
85}
86
87/// A solid circle. (b2Circle)
88#[derive(Debug, Clone, Copy, PartialEq, Default)]
89pub struct Circle {
90 /// The local center
91 pub center: Vec2,
92 /// The radius
93 pub radius: f32,
94}
95
96/// A solid capsule can be viewed as two semicircles connected by a rectangle.
97/// (b2Capsule)
98#[derive(Debug, Clone, Copy, PartialEq, Default)]
99pub struct Capsule {
100 /// Local center of the first semicircle
101 pub center1: Vec2,
102 /// Local center of the second semicircle
103 pub center2: Vec2,
104 /// The radius of the semicircles
105 pub radius: f32,
106}
107
108/// A solid convex polygon. It is assumed that the interior of the polygon is
109/// to the left of each edge. Polygons have a maximum number of vertices equal
110/// to [`MAX_POLYGON_VERTICES`]. In most cases you should not need many
111/// vertices for a convex polygon. (b2Polygon)
112///
113/// @warning DO NOT fill this out manually, instead use a helper function like
114/// `make_polygon` or `make_box`.
115#[derive(Debug, Clone, Copy, PartialEq)]
116pub struct Polygon {
117 /// The polygon vertices
118 pub vertices: [Vec2; MAX_POLYGON_VERTICES],
119 /// The outward normal vectors of the polygon sides
120 pub normals: [Vec2; MAX_POLYGON_VERTICES],
121 /// The centroid of the polygon
122 pub centroid: Vec2,
123 /// The external radius for rounded polygons
124 pub radius: f32,
125 /// The number of polygon vertices
126 pub count: i32,
127}
128
129impl Default for Polygon {
130 fn default() -> Self {
131 Polygon {
132 vertices: [VEC2_ZERO; MAX_POLYGON_VERTICES],
133 normals: [VEC2_ZERO; MAX_POLYGON_VERTICES],
134 centroid: VEC2_ZERO,
135 radius: 0.0,
136 count: 0,
137 }
138 }
139}
140
141/// A line segment with two-sided collision. (b2Segment)
142#[derive(Debug, Clone, Copy, PartialEq, Default)]
143pub struct Segment {
144 /// The first point
145 pub point1: Vec2,
146 /// The second point
147 pub point2: Vec2,
148}
149
150/// A line segment with one-sided collision. Only collides on the right side.
151/// Several of these are generated for a chain shape.
152/// ghost1 -> point1 -> point2 -> ghost2. (b2ChainSegment)
153#[derive(Debug, Clone, Copy, PartialEq, Default)]
154pub struct ChainSegment {
155 /// The tail ghost vertex
156 pub ghost1: Vec2,
157 /// The line segment
158 pub segment: Segment,
159 /// The head ghost vertex
160 pub ghost2: Vec2,
161 /// The owning chain shape index (internal usage only)
162 pub chain_id: i32,
163}
164
165/// Shape type. (types.h: b2ShapeType)
166#[derive(Debug, Clone, Copy, PartialEq, Eq)]
167pub enum ShapeType {
168 /// A circle with an offset
169 Circle,
170 /// A capsule is an extruded circle
171 Capsule,
172 /// A line segment
173 Segment,
174 /// A convex polygon
175 Polygon,
176 /// A line segment owned by a chain shape
177 ChainSegment,
178}
179
180/// The number of shape types. (types.h: b2_shapeTypeCount)
181pub const SHAPE_TYPE_COUNT: usize = 5;
182
183/// The geometry payload of a shape. The C `b2Shape` stores a `b2ShapeType` tag
184/// plus a union of the concrete geometries; in Rust that pairing is an enum.
185/// The internal shape module embeds this.
186#[derive(Debug, Clone, Copy, PartialEq)]
187pub enum ShapeGeometry {
188 Circle(Circle),
189 Capsule(Capsule),
190 Segment(Segment),
191 Polygon(Polygon),
192 ChainSegment(ChainSegment),
193}
194
195impl ShapeGeometry {
196 /// The shape type tag for this geometry.
197 pub fn shape_type(&self) -> ShapeType {
198 match self {
199 ShapeGeometry::Circle(_) => ShapeType::Circle,
200 ShapeGeometry::Capsule(_) => ShapeType::Capsule,
201 ShapeGeometry::Segment(_) => ShapeType::Segment,
202 ShapeGeometry::Polygon(_) => ShapeType::Polygon,
203 ShapeGeometry::ChainSegment(_) => ShapeType::ChainSegment,
204 }
205 }
206}
207
208/// A manifold point is a contact point belonging to a contact manifold. It
209/// holds details related to the geometry and dynamics of the contact points.
210/// Box2D uses speculative collision so some contact points may be separated.
211/// (b2ManifoldPoint)
212#[derive(Debug, Clone, Copy, PartialEq, Default)]
213pub struct ManifoldPoint {
214 /// Location of the contact point relative to body A's center of mass in
215 /// world space.
216 pub anchor_a: Vec2,
217 /// Location of the contact point relative to body B's center of mass in
218 /// world space.
219 pub anchor_b: Vec2,
220 /// The separation of the contact point, negative if penetrating
221 pub separation: f32,
222 /// Cached separation used for contact recycling
223 pub base_separation: f32,
224 /// The impulse along the manifold normal vector
225 pub normal_impulse: f32,
226 /// The friction impulse
227 pub tangent_impulse: f32,
228 /// The total normal impulse applied across sub-stepping and restitution
229 pub total_normal_impulse: f32,
230 /// Relative normal velocity pre-solve. Used for hit events.
231 pub normal_velocity: f32,
232 /// Uniquely identifies a contact point between two shapes
233 pub id: u16,
234 /// Did this contact point exist the previous step?
235 pub persisted: bool,
236}
237
238/// A contact manifold describes the contact points between colliding shapes.
239/// (b2Manifold)
240#[derive(Debug, Clone, Copy, PartialEq, Default)]
241pub struct Manifold {
242 /// The unit normal vector in world space, points from shape A to body B
243 pub normal: Vec2,
244 /// Angular impulse applied for rolling resistance
245 pub rolling_impulse: f32,
246 /// The manifold points, up to two are possible in 2D
247 pub points: [ManifoldPoint; 2],
248 /// The number of contact points, will be 0, 1, or 2
249 pub point_count: i32,
250}
251
252/// Contact manifold point in local coordinates (frame A).
253/// (b2LocalManifoldPoint)
254#[derive(Debug, Clone, Copy, PartialEq, Default)]
255pub struct LocalManifoldPoint {
256 /// Contact point in frame A
257 pub point: Vec2,
258 /// The separation of the contact point, negative if penetrating
259 pub separation: f32,
260 /// Uniquely identifies a contact point between two shapes
261 pub id: u16,
262}
263
264/// Contact manifold in local coordinates (frame A). (b2LocalManifold)
265#[derive(Debug, Clone, Copy, PartialEq, Default)]
266pub struct LocalManifold {
267 /// The unit normal vector in frame A, points from shape A to shape B
268 pub normal: Vec2,
269 /// The manifold points, up to two are possible in 2D
270 pub points: [LocalManifoldPoint; 2],
271 /// The number of contact points, will be 0, 1, or 2
272 pub point_count: i32,
273}
274
275/// These are the collision planes returned from b2World_CollideMover.
276/// The plane and point are relative to the query origin, matching the mover
277/// capsule. (b2PlaneResult)
278#[derive(Debug, Clone, Copy, PartialEq)]
279pub struct PlaneResult {
280 /// The collision plane between the mover and a convex shape
281 pub plane: Plane,
282 /// The collision point on the shape.
283 pub point: Vec2,
284 /// Did the collision register a hit? If not this plane should be ignored.
285 pub hit: bool,
286}
287
288impl Default for PlaneResult {
289 fn default() -> Self {
290 PlaneResult {
291 plane: Plane {
292 normal: VEC2_ZERO,
293 offset: 0.0,
294 },
295 point: VEC2_ZERO,
296 hit: false,
297 }
298 }
299}