Skip to main content

box2d_rs/
b2_collision.rs

1use crate::b2_math::*;
2use crate::b2_common::B2_MAX_MANIFOLD_POINTS;
3use crate::b2_shape::*;
4use crate::private::collision as private;
5use crate::shapes::b2_circle_shape::*;
6use crate::shapes::b2_edge_shape::*;
7use crate::shapes::b2_polygon_shape::*;
8
9/// @file
10/// Structures and functions used for computing contact points, distance
11/// queries, and TOI queries.
12
13pub const B2_NULL_FEATURE: u8 = std::u8::MAX;
14
15pub enum B2contactFeatureType {
16    EVertex = 0,
17    EFace = 1,
18}
19
20/// The features that intersect to form the contact point
21/// This must be 4 bytes or less.
22#[derive(Clone, Default, Copy, Debug, PartialEq)]
23pub struct B2contactFeature {
24    /// Feature index on shape_a
25    pub index_a: u8,
26    /// Feature index on shape_b
27    pub index_b: u8,
28    /// The feature type on shape_a
29    pub type_a: u8,
30    /// The feature type on shape_b
31    pub type_b: u8,
32}
33
34/// Contact ids to facilitate warm starting.
35#[derive(Clone, Default, Copy, Debug, PartialEq)]
36pub struct B2contactId {
37    pub cf: B2contactFeature,
38}
39
40/// A manifold point is a contact point belonging to a contact
41/// manifold. It holds details related to the geometry and dynamics
42/// of the contact points.
43/// The local point usage depends on the manifold type:
44/// -e_circles: the local center of circle_b
45/// -e_faceA: the local center of cirlceB or the clip point of polygon_b
46/// -e_faceB: the clip point of polygon_a
47/// This structure is stored across time steps, so we keep it small.
48/// Note: the impulses are used for internal caching and may not
49/// provide reliable contact forces, especially for high speed collisions.
50#[derive(Clone, Copy, Debug, Default)]
51pub struct B2manifoldPoint {
52    ///< usage depends on manifold type
53    pub local_point: B2vec2,
54    ///< the non-penetration impulse
55    pub normal_impulse: f32,
56    ///< the friction impulse
57    pub tangent_impulse: f32,
58    ///< uniquely identifies a contact point between two shapes
59    pub id: B2contactId,
60}
61
62#[derive(Clone, Copy, Debug)]
63pub enum B2manifoldType {
64    ECircles,
65    EFaceA,
66    EFaceB,
67}
68
69impl Default for B2manifoldType {
70    fn default() -> Self {
71        return B2manifoldType::ECircles;
72    }
73}
74
75impl Default for B2manifold {
76    fn default() -> Self {
77        return B2manifold {
78            points: [B2manifoldPoint::default();B2_MAX_MANIFOLD_POINTS],
79            local_normal: B2vec2::default(),
80            local_point: B2vec2::default(),
81            manifold_type: B2manifoldType::ECircles,
82            point_count: 0,
83        };
84    }
85}
86
87/// A manifold for two touching convex shapes.
88/// Box2D supports multiple types of contact:
89/// - clip point versus plane with radius
90/// - point versus point with radius (circles)
91/// The local point usage depends on the manifold type:
92/// -e_circles: the local center of circle_a
93/// -e_faceA: the center of faceA
94/// -e_faceB: the center of faceB
95/// Similarly the local normal usage:
96/// -e_circles: not used
97/// -e_faceA: the normal on polygon_a
98/// -e_faceB: the normal on polygon_b
99/// We store contacts in this way so that position correction can
100/// account for movement, which is critical for continuous physics.
101/// All contact scenarios must be expressed in one of these types.
102/// This structure is stored across time steps, so we keep it small.
103#[derive(Clone, Copy, Debug)]
104pub struct B2manifold {
105    /// the points of contact
106    pub points: [B2manifoldPoint; B2_MAX_MANIFOLD_POINTS],
107    ///< not use for B2manifoldType::e_points
108    pub local_normal: B2vec2,
109    ///< usage depends on manifold type
110    pub local_point: B2vec2,
111    pub manifold_type: B2manifoldType,
112    ///< the number of manifold points
113    pub point_count: usize,
114}
115
116/// This is used to compute the current state of a contact manifold.
117#[derive(Default, Clone, Copy, Debug)]
118pub struct B2worldManifold {
119    ///< world vector pointing from A to b
120    pub normal: B2vec2,
121    ///< world contact point (point of intersection)
122    pub points: [B2vec2; B2_MAX_MANIFOLD_POINTS],
123    ///< a negative value indicates overlap, in meters
124    pub separations: [f32; B2_MAX_MANIFOLD_POINTS],
125}
126
127impl B2worldManifold {
128    /// evaluate the manifold with supplied transforms. This assumes
129    /// modest motion from the original state. This does not change the
130    /// point count, impulses, etc. The radii must come from the shapes
131    /// that generated the manifold.
132    pub fn initialize(
133        &mut self,
134        manifold: &B2manifold,
135        xf_a: B2Transform,
136        radius_a: f32,
137        xf_b: B2Transform,
138        radius_b: f32,
139    ) {
140        private::b2_collision::b2_world_manifold_initialize(
141            self, manifold, xf_a, radius_a, xf_b, radius_b,
142        );
143    }
144}
145
146/// This is used for determining the state of contact points.
147#[derive(Clone, Copy, Debug, PartialEq)]
148pub enum B2pointState {
149    ///< point does not exist
150    B2NullState,
151    ///< point was added in the update
152    B2AddState,
153    ///< point persisted across the update
154    B2PersistState,
155    ///< point was removed in the update
156    B2RemoveState,
157}
158
159impl Default for B2pointState {
160    fn default() -> Self {
161        B2pointState::B2NullState
162    }
163}
164
165/// Compute the point states given two manifolds. The states pertain to the transition from manifold1
166/// to manifold2. So state1 is either persist or remove while state2 is either add or persist.
167pub fn b2_get_point_states(
168    state1: &mut [B2pointState; B2_MAX_MANIFOLD_POINTS],
169    state2: &mut [B2pointState; B2_MAX_MANIFOLD_POINTS],
170    manifold1: &B2manifold,
171    manifold2: &B2manifold,
172) {
173    private::b2_collision::b2_get_point_states(state1, state2, manifold1, manifold2);
174}
175
176/// Used for computing contact manifolds.
177#[derive(Clone, Default, Copy, Debug)]
178pub struct B2clipVertex {
179    pub v: B2vec2,
180    pub id: B2contactId,
181}
182
183/// Ray-cast input data. The ray extends from p1 to p1 + max_fraction * (p2 - p1).
184#[derive(Clone, Copy, Debug)]
185pub struct B2rayCastInput {
186    pub p1: B2vec2,
187    pub p2: B2vec2,
188    pub max_fraction: f32,
189}
190
191/// Ray-cast output data. The ray hits at p1 + fraction * (p2 - p1), where p1 and p2
192/// come from b2RayCastInput.
193#[derive(Default, Clone, Copy, Debug)]
194pub struct B2rayCastOutput {
195    pub normal: B2vec2,
196    pub fraction: f32,
197}
198
199/// An axis aligned bounding box.
200#[derive(Default, Clone, Copy, Debug)]
201pub struct B2AABB {
202    ///< the lower vertex
203    pub lower_bound: B2vec2,
204    ///< the upper vertex
205    pub upper_bound: B2vec2,
206}
207
208impl B2AABB {
209    /// Verify that the bounds are sorted.
210    pub fn is_valid(self) -> bool {
211        return b2_aabb_is_valid(self);
212    }
213
214    /// Get the center of the AABB.
215    pub fn get_center(self) -> B2vec2 {
216        return 0.5 * (self.lower_bound + self.upper_bound);
217    }
218
219    /// Get the extents of the AABB (half-widths).
220    pub fn get_extents(self) -> B2vec2 {
221        return 0.5 * (self.upper_bound - self.lower_bound);
222    }
223
224    /// Get the perimeter length
225    pub fn get_perimeter(self) -> f32 {
226        let wx = self.upper_bound.x - self.lower_bound.x;
227        let wy = self.upper_bound.y - self.lower_bound.y;
228        return 2.0 * (wx + wy);
229    }
230
231    /// Combine an AABB into this one.
232    pub fn combine(&mut self, aabb: B2AABB) {
233        self.lower_bound = b2_min_vec2(self.lower_bound, aabb.lower_bound);
234        self.upper_bound = b2_max_vec2(self.upper_bound, aabb.upper_bound);
235    }
236
237    /// Combine two AABBs into this one.
238    pub fn combine_two(&mut self, aabb1: B2AABB, aabb2: B2AABB) {
239        self.lower_bound = b2_min_vec2(aabb1.lower_bound, aabb2.lower_bound);
240        self.upper_bound = b2_max_vec2(aabb1.upper_bound, aabb2.upper_bound);
241    }
242
243    /// Does this aabb contain the provided AABB.
244    pub fn contains(self, aabb: &B2AABB) -> bool {
245        let mut result = true;
246        result = result && self.lower_bound.x <= aabb.lower_bound.x;
247        result = result && self.lower_bound.y <= aabb.lower_bound.y;
248        result = result && aabb.upper_bound.x <= self.upper_bound.x;
249        result = result && aabb.upper_bound.y <= self.upper_bound.y;
250        return result;
251    }
252
253    pub fn ray_cast(self, output: &mut B2rayCastOutput, input: &B2rayCastInput) -> bool {
254        return private::b2_collision::b2_aabb_ray_cast(self, output, input);
255    }
256}
257
258/// Compute the collision manifold between two circles.
259pub fn b2_collide_circles(
260    manifold: &mut B2manifold,
261    circle_a: &B2circleShape,
262    xf_a: &B2Transform,
263    circle_b: &B2circleShape,
264    xf_b: &B2Transform,
265) {
266    private::b2_collide_circle::b2_collide_circles(manifold, circle_a, xf_a, circle_b, xf_b);
267}
268
269/// Compute the collision manifold between a polygon and a circle.
270pub fn b2_collide_polygon_and_circle(
271    manifold: &mut B2manifold,
272    polygon_a: &B2polygonShape,
273    xf_a: &B2Transform,
274    circle_b: &B2circleShape,
275    xf_b: &B2Transform,
276) {
277    private::b2_collide_circle::b2_collide_polygon_and_circle(
278        manifold, polygon_a, xf_a, circle_b, xf_b,
279    );
280}
281
282/// Compute the collision manifold between two polygons.
283pub fn b2_collide_polygons(
284    manifold: &mut B2manifold,
285    polygon_a: &B2polygonShape,
286    xf_a: &B2Transform,
287    polygon_b: &B2polygonShape,
288    xf_b: &B2Transform,
289) {
290    private::b2_collide_polygon::b2_collide_polygons(
291        manifold, *polygon_a, *xf_a, *polygon_b, *xf_b,
292    );
293}
294
295/// Compute the collision manifold between an edge and a circle.
296pub fn b2_collide_edge_and_circle(
297    manifold: &mut B2manifold,
298    edge_a: &B2edgeShape,
299    xf_a: &B2Transform,
300    circle_b: &B2circleShape,
301    xf_b: &B2Transform,
302) {
303    private::b2_collide_edge::b2_collide_edge_and_circle(manifold, edge_a, xf_a, circle_b, xf_b);
304}
305
306/// Compute the collision manifold between an edge and a polygon.
307pub fn b2_collide_edge_and_polygon(
308    manifold: &mut B2manifold,
309    edge_a: &B2edgeShape,
310    xf_a: &B2Transform,
311    polygon_b: &B2polygonShape,
312    xf_b: &B2Transform,
313) {
314    private::b2_collide_edge::b2_collide_edge_and_polygon(manifold, edge_a, xf_a, polygon_b, xf_b);
315}
316
317// /// Clipping for contact manifolds.
318pub fn b2_clip_segment_to_line(
319    v_out: &mut [B2clipVertex; 2],
320    v_in: [B2clipVertex; 2],
321    normal: B2vec2,
322    offset: f32,
323    vertex_index_a: usize,
324) -> usize {
325    return private::b2_collision::b2_clip_segment_to_line(
326        v_out,
327        v_in,
328        normal,
329        offset,
330        vertex_index_a,
331    );
332}
333
334/// Determine if two generic shapes overlap.
335pub fn b2_test_overlap_shapes(
336    shape_a: ShapePtr,
337    index_a: usize,
338    shape_b: ShapePtr,
339    index_b: usize,
340    xf_a: B2Transform,
341    xf_b: B2Transform,
342) -> bool {
343    return private::b2_collision::b2_test_overlap(shape_a, index_a, shape_b, index_b, xf_a, xf_b);
344}
345
346// ---------------- Inline Functions ------------------------------------------
347
348pub fn b2_aabb_is_valid(self_: B2AABB) -> bool {
349    let d: B2vec2 = self_.upper_bound - self_.lower_bound;
350    let mut valid: bool = d.x >= 0.0 && d.y >= 0.0;
351    valid = valid && self_.lower_bound.is_valid() && self_.upper_bound.is_valid();
352    return valid;
353}
354
355pub fn b2_test_overlap(a: B2AABB, b: B2AABB) -> bool {
356    let d1 = b.lower_bound - a.upper_bound;
357    let d2 = a.lower_bound - b.upper_bound;
358
359    if d1.x > 0.0 || d1.y > 0.0 {
360        return false;
361    }
362
363    if d2.x > 0.0 || d2.y > 0.0 {
364        return false;
365    }
366
367    return true;
368}