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}