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/// This holds the mass data computed for a shape. (b2MassData)
59#[derive(Debug, Clone, Copy, PartialEq, Default)]
60pub struct MassData {
61    /// The mass of the shape, usually in kilograms.
62    pub mass: f32,
63    /// The position of the shape's centroid relative to the shape's origin.
64    pub center: Vec2,
65    /// The rotational inertia of the shape about the shape center.
66    pub rotational_inertia: f32,
67}
68
69/// A solid circle. (b2Circle)
70#[derive(Debug, Clone, Copy, PartialEq, Default)]
71pub struct Circle {
72    /// The local center
73    pub center: Vec2,
74    /// The radius
75    pub radius: f32,
76}
77
78/// A solid capsule can be viewed as two semicircles connected by a rectangle.
79/// (b2Capsule)
80#[derive(Debug, Clone, Copy, PartialEq, Default)]
81pub struct Capsule {
82    /// Local center of the first semicircle
83    pub center1: Vec2,
84    /// Local center of the second semicircle
85    pub center2: Vec2,
86    /// The radius of the semicircles
87    pub radius: f32,
88}
89
90/// A solid convex polygon. It is assumed that the interior of the polygon is
91/// to the left of each edge. Polygons have a maximum number of vertices equal
92/// to [`MAX_POLYGON_VERTICES`]. In most cases you should not need many
93/// vertices for a convex polygon. (b2Polygon)
94///
95/// @warning DO NOT fill this out manually, instead use a helper function like
96/// `make_polygon` or `make_box`.
97#[derive(Debug, Clone, Copy, PartialEq)]
98pub struct Polygon {
99    /// The polygon vertices
100    pub vertices: [Vec2; MAX_POLYGON_VERTICES],
101    /// The outward normal vectors of the polygon sides
102    pub normals: [Vec2; MAX_POLYGON_VERTICES],
103    /// The centroid of the polygon
104    pub centroid: Vec2,
105    /// The external radius for rounded polygons
106    pub radius: f32,
107    /// The number of polygon vertices
108    pub count: i32,
109}
110
111impl Default for Polygon {
112    fn default() -> Self {
113        Polygon {
114            vertices: [VEC2_ZERO; MAX_POLYGON_VERTICES],
115            normals: [VEC2_ZERO; MAX_POLYGON_VERTICES],
116            centroid: VEC2_ZERO,
117            radius: 0.0,
118            count: 0,
119        }
120    }
121}
122
123/// A line segment with two-sided collision. (b2Segment)
124#[derive(Debug, Clone, Copy, PartialEq, Default)]
125pub struct Segment {
126    /// The first point
127    pub point1: Vec2,
128    /// The second point
129    pub point2: Vec2,
130}
131
132/// A line segment with one-sided collision. Only collides on the right side.
133/// Several of these are generated for a chain shape.
134/// ghost1 -> point1 -> point2 -> ghost2. (b2ChainSegment)
135#[derive(Debug, Clone, Copy, PartialEq, Default)]
136pub struct ChainSegment {
137    /// The tail ghost vertex
138    pub ghost1: Vec2,
139    /// The line segment
140    pub segment: Segment,
141    /// The head ghost vertex
142    pub ghost2: Vec2,
143    /// The owning chain shape index (internal usage only)
144    pub chain_id: i32,
145}
146
147/// Shape type. (types.h: b2ShapeType)
148#[derive(Debug, Clone, Copy, PartialEq, Eq)]
149pub enum ShapeType {
150    /// A circle with an offset
151    Circle,
152    /// A capsule is an extruded circle
153    Capsule,
154    /// A line segment
155    Segment,
156    /// A convex polygon
157    Polygon,
158    /// A line segment owned by a chain shape
159    ChainSegment,
160}
161
162/// The number of shape types. (types.h: b2_shapeTypeCount)
163pub const SHAPE_TYPE_COUNT: usize = 5;
164
165/// The geometry payload of a shape. The C `b2Shape` stores a `b2ShapeType` tag
166/// plus a union of the concrete geometries; in Rust that pairing is an enum.
167/// The internal shape module embeds this.
168#[derive(Debug, Clone, Copy, PartialEq)]
169pub enum ShapeGeometry {
170    Circle(Circle),
171    Capsule(Capsule),
172    Segment(Segment),
173    Polygon(Polygon),
174    ChainSegment(ChainSegment),
175}
176
177impl ShapeGeometry {
178    /// The shape type tag for this geometry.
179    pub fn shape_type(&self) -> ShapeType {
180        match self {
181            ShapeGeometry::Circle(_) => ShapeType::Circle,
182            ShapeGeometry::Capsule(_) => ShapeType::Capsule,
183            ShapeGeometry::Segment(_) => ShapeType::Segment,
184            ShapeGeometry::Polygon(_) => ShapeType::Polygon,
185            ShapeGeometry::ChainSegment(_) => ShapeType::ChainSegment,
186        }
187    }
188}
189
190/// A manifold point is a contact point belonging to a contact manifold. It
191/// holds details related to the geometry and dynamics of the contact points.
192/// Box2D uses speculative collision so some contact points may be separated.
193/// (b2ManifoldPoint)
194#[derive(Debug, Clone, Copy, PartialEq, Default)]
195pub struct ManifoldPoint {
196    /// Location of the contact point relative to body A's center of mass in
197    /// world space.
198    pub anchor_a: Vec2,
199    /// Location of the contact point relative to body B's center of mass in
200    /// world space.
201    pub anchor_b: Vec2,
202    /// The separation of the contact point, negative if penetrating
203    pub separation: f32,
204    /// Cached separation used for contact recycling
205    pub base_separation: f32,
206    /// The impulse along the manifold normal vector
207    pub normal_impulse: f32,
208    /// The friction impulse
209    pub tangent_impulse: f32,
210    /// The total normal impulse applied across sub-stepping and restitution
211    pub total_normal_impulse: f32,
212    /// Relative normal velocity pre-solve. Used for hit events.
213    pub normal_velocity: f32,
214    /// Uniquely identifies a contact point between two shapes
215    pub id: u16,
216    /// Did this contact point exist the previous step?
217    pub persisted: bool,
218}
219
220/// A contact manifold describes the contact points between colliding shapes.
221/// (b2Manifold)
222#[derive(Debug, Clone, Copy, PartialEq, Default)]
223pub struct Manifold {
224    /// The unit normal vector in world space, points from shape A to body B
225    pub normal: Vec2,
226    /// Angular impulse applied for rolling resistance
227    pub rolling_impulse: f32,
228    /// The manifold points, up to two are possible in 2D
229    pub points: [ManifoldPoint; 2],
230    /// The number of contact points, will be 0, 1, or 2
231    pub point_count: i32,
232}
233
234/// Contact manifold point in local coordinates (frame A).
235/// (b2LocalManifoldPoint)
236#[derive(Debug, Clone, Copy, PartialEq, Default)]
237pub struct LocalManifoldPoint {
238    /// Contact point in frame A
239    pub point: Vec2,
240    /// The separation of the contact point, negative if penetrating
241    pub separation: f32,
242    /// Uniquely identifies a contact point between two shapes
243    pub id: u16,
244}
245
246/// Contact manifold in local coordinates (frame A). (b2LocalManifold)
247#[derive(Debug, Clone, Copy, PartialEq, Default)]
248pub struct LocalManifold {
249    /// The unit normal vector in frame A, points from shape A to shape B
250    pub normal: Vec2,
251    /// The manifold points, up to two are possible in 2D
252    pub points: [LocalManifoldPoint; 2],
253    /// The number of contact points, will be 0, 1, or 2
254    pub point_count: i32,
255}
256
257/// These are the collision planes returned from b2World_CollideMover.
258/// The plane and point are relative to the query origin, matching the mover
259/// capsule. (b2PlaneResult)
260#[derive(Debug, Clone, Copy, PartialEq)]
261pub struct PlaneResult {
262    /// The collision plane between the mover and a convex shape
263    pub plane: Plane,
264    /// The collision point on the shape.
265    pub point: Vec2,
266    /// Did the collision register a hit? If not this plane should be ignored.
267    pub hit: bool,
268}
269
270impl Default for PlaneResult {
271    fn default() -> Self {
272        PlaneResult {
273            plane: Plane {
274                normal: VEC2_ZERO,
275                offset: 0.0,
276            },
277            point: VEC2_ZERO,
278            hit: false,
279        }
280    }
281}