Skip to main content

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}