Skip to main content

box2d_rust/geometry/
shape_cast.rs

1// Shape cast wrappers and mover collision from geometry.c.
2// SPDX-FileCopyrightText: 2023 Erin Catto
3// SPDX-License-Identifier: MIT
4
5use crate::collision::{
6    Capsule, CastOutput, Circle, PlaneResult, Polygon, Segment, ShapeCastInput,
7};
8use crate::distance::{
9    make_proxy, shape_cast, shape_distance, DistanceInput, ShapeCastPairInput, SimplexCache,
10};
11use crate::math_functions::{Plane, TRANSFORM_IDENTITY};
12
13/// Shape cast versus a circle. (b2ShapeCastCircle)
14pub fn shape_cast_circle(shape: &Circle, input: &ShapeCastInput) -> CastOutput {
15    let pair_input = ShapeCastPairInput {
16        proxy_a: make_proxy(&[shape.center], shape.radius),
17        proxy_b: input.proxy,
18        transform: TRANSFORM_IDENTITY,
19        translation_b: input.translation,
20        max_fraction: input.max_fraction,
21        can_encroach: input.can_encroach,
22    };
23
24    shape_cast(&pair_input)
25}
26
27/// Shape cast versus a capsule. (b2ShapeCastCapsule)
28pub fn shape_cast_capsule(shape: &Capsule, input: &ShapeCastInput) -> CastOutput {
29    let pair_input = ShapeCastPairInput {
30        proxy_a: make_proxy(&[shape.center1, shape.center2], shape.radius),
31        proxy_b: input.proxy,
32        transform: TRANSFORM_IDENTITY,
33        translation_b: input.translation,
34        max_fraction: input.max_fraction,
35        can_encroach: input.can_encroach,
36    };
37
38    shape_cast(&pair_input)
39}
40
41/// Shape cast versus a line segment. (b2ShapeCastSegment)
42pub fn shape_cast_segment(shape: &Segment, input: &ShapeCastInput) -> CastOutput {
43    let pair_input = ShapeCastPairInput {
44        proxy_a: make_proxy(&[shape.point1, shape.point2], 0.0),
45        proxy_b: input.proxy,
46        transform: TRANSFORM_IDENTITY,
47        translation_b: input.translation,
48        max_fraction: input.max_fraction,
49        can_encroach: input.can_encroach,
50    };
51
52    shape_cast(&pair_input)
53}
54
55/// Shape cast versus a convex polygon. (b2ShapeCastPolygon)
56pub fn shape_cast_polygon(shape: &Polygon, input: &ShapeCastInput) -> CastOutput {
57    let pair_input = ShapeCastPairInput {
58        proxy_a: make_proxy(&shape.vertices[..shape.count as usize], shape.radius),
59        proxy_b: input.proxy,
60        transform: TRANSFORM_IDENTITY,
61        translation_b: input.translation,
62        max_fraction: input.max_fraction,
63        can_encroach: input.can_encroach,
64    };
65
66    shape_cast(&pair_input)
67}
68
69/// Collide a mover capsule against a circle. (b2CollideMoverAndCircle)
70pub fn collide_mover_and_circle(mover: &Capsule, shape: &Circle) -> PlaneResult {
71    let distance_input = DistanceInput {
72        proxy_a: make_proxy(&[shape.center], 0.0),
73        proxy_b: make_proxy(&[mover.center1, mover.center2], mover.radius),
74        transform: TRANSFORM_IDENTITY,
75        use_radii: false,
76    };
77
78    let total_radius = mover.radius + shape.radius;
79
80    let mut cache = SimplexCache::default();
81    let distance_output = shape_distance(&distance_input, &mut cache, None);
82
83    if distance_output.distance <= total_radius {
84        let plane = Plane {
85            normal: distance_output.normal,
86            offset: total_radius - distance_output.distance,
87        };
88        return PlaneResult {
89            plane,
90            point: distance_output.point_a,
91            hit: true,
92        };
93    }
94
95    PlaneResult::default()
96}
97
98/// Collide a mover capsule against a capsule. (b2CollideMoverAndCapsule)
99pub fn collide_mover_and_capsule(mover: &Capsule, shape: &Capsule) -> PlaneResult {
100    let distance_input = DistanceInput {
101        proxy_a: make_proxy(&[shape.center1, shape.center2], 0.0),
102        proxy_b: make_proxy(&[mover.center1, mover.center2], mover.radius),
103        transform: TRANSFORM_IDENTITY,
104        use_radii: false,
105    };
106
107    let total_radius = mover.radius + shape.radius;
108
109    let mut cache = SimplexCache::default();
110    let distance_output = shape_distance(&distance_input, &mut cache, None);
111
112    if distance_output.distance <= total_radius {
113        let plane = Plane {
114            normal: distance_output.normal,
115            offset: total_radius - distance_output.distance,
116        };
117        return PlaneResult {
118            plane,
119            point: distance_output.point_a,
120            hit: true,
121        };
122    }
123
124    PlaneResult::default()
125}
126
127/// Collide a mover capsule against a polygon. (b2CollideMoverAndPolygon)
128pub fn collide_mover_and_polygon(mover: &Capsule, shape: &Polygon) -> PlaneResult {
129    let distance_input = DistanceInput {
130        proxy_a: make_proxy(&shape.vertices[..shape.count as usize], shape.radius),
131        proxy_b: make_proxy(&[mover.center1, mover.center2], mover.radius),
132        transform: TRANSFORM_IDENTITY,
133        use_radii: false,
134    };
135
136    let total_radius = mover.radius + shape.radius;
137
138    let mut cache = SimplexCache::default();
139    let distance_output = shape_distance(&distance_input, &mut cache, None);
140
141    if distance_output.distance <= total_radius {
142        let plane = Plane {
143            normal: distance_output.normal,
144            offset: total_radius - distance_output.distance,
145        };
146        return PlaneResult {
147            plane,
148            point: distance_output.point_a,
149            hit: true,
150        };
151    }
152
153    PlaneResult::default()
154}
155
156/// Collide a mover capsule against a segment. (b2CollideMoverAndSegment)
157pub fn collide_mover_and_segment(mover: &Capsule, shape: &Segment) -> PlaneResult {
158    let distance_input = DistanceInput {
159        proxy_a: make_proxy(&[shape.point1, shape.point2], 0.0),
160        proxy_b: make_proxy(&[mover.center1, mover.center2], mover.radius),
161        transform: TRANSFORM_IDENTITY,
162        use_radii: false,
163    };
164
165    let total_radius = mover.radius;
166
167    let mut cache = SimplexCache::default();
168    let distance_output = shape_distance(&distance_input, &mut cache, None);
169
170    if distance_output.distance <= total_radius {
171        let plane = Plane {
172            normal: distance_output.normal,
173            offset: total_radius - distance_output.distance,
174        };
175        return PlaneResult {
176            plane,
177            point: distance_output.point_a,
178            hit: true,
179        };
180    }
181
182    PlaneResult::default()
183}