quadtree/
collision_detection.rs

1use crate::error::QuadtreeResult;
2use crate::quadtree::{validate_circle_radius, validate_rect_dims};
3use crate::shapes::{Circle, Rectangle, ShapeEnum};
4
5// Check that Rectangle inner is fully contained in Rectangle outer, including on the boundary
6pub fn rectangle_contains_rectangle(outer: &Rectangle, inner: &Rectangle) -> QuadtreeResult<bool> {
7    validate_rect_dims(outer.width, outer.height)?;
8    validate_rect_dims(inner.width, inner.height)?;
9    Ok(outer.left() <= inner.left()
10        && outer.right() >= inner.right()
11        && outer.top() <= inner.top()
12        && outer.bottom() >= inner.bottom())
13}
14
15/// Note: touching edges are not treated as collisions.
16pub fn rectangle_rectangle(a: &Rectangle, b: &Rectangle) -> QuadtreeResult<bool> {
17    validate_rect_dims(a.width, a.height)?;
18    validate_rect_dims(b.width, b.height)?;
19    Ok(
20        a.left() < b.right()
21            && a.right() > b.left()
22            && a.top() < b.bottom()
23            && a.bottom() > b.top(),
24    )
25}
26
27/// Note: touching edges are not treated as collisions.
28pub fn circle_circle(a: &Circle, b: &Circle) -> QuadtreeResult<bool> {
29    validate_circle_radius(a.radius)?;
30    validate_circle_radius(b.radius)?;
31    let dx = a.x - b.x;
32    let dy = a.y - b.y;
33    let distance_sq = dx * dx + dy * dy;
34    let radius_sum = a.radius + b.radius;
35    Ok(distance_sq < radius_sum * radius_sum)
36}
37
38/// Note: touching edges are not treated as collisions.
39pub fn circle_rectangle(circle: &Circle, rectangle: &Rectangle) -> QuadtreeResult<bool> {
40    validate_circle_radius(circle.radius)?;
41    validate_rect_dims(rectangle.width, rectangle.height)?;
42    let dx = (circle.x - rectangle.x).abs();
43    let dy = (circle.y - rectangle.y).abs();
44
45    let half_rect_width = rectangle.width / 2.0;
46    let half_rect_height = rectangle.height / 2.0;
47
48    // Check if the circle is outside the rectangle's bounds
49    if dx >= half_rect_width + circle.radius || dy >= half_rect_height + circle.radius {
50        return Ok(false);
51    }
52
53    // Check if the circle's center is inside the rectangle
54    if dx < half_rect_width || dy < half_rect_height {
55        return Ok(true);
56    }
57
58    // Check if the circle intersects the rectangle's corner
59    let corner_dx = dx - half_rect_width;
60    let corner_dy = dy - half_rect_height;
61    let corner_distance_sq = corner_dx * corner_dx + corner_dy * corner_dy;
62
63    Ok(corner_distance_sq < circle.radius * circle.radius)
64}
65
66/// Note: touching edges are not treated as collisions.
67pub fn shape_shape(a: &ShapeEnum, b: &ShapeEnum) -> QuadtreeResult<bool> {
68    match (a, b) {
69        (ShapeEnum::Circle(circle_a), ShapeEnum::Circle(circle_b)) => {
70            circle_circle(circle_a, circle_b)
71        }
72        (ShapeEnum::Circle(circle), ShapeEnum::Rectangle(rectangle))
73        | (ShapeEnum::Rectangle(rectangle), ShapeEnum::Circle(circle)) => {
74            circle_rectangle(circle, rectangle)
75        }
76        (ShapeEnum::Rectangle(rectangle_a), ShapeEnum::Rectangle(rectangle_b)) => {
77            rectangle_rectangle(rectangle_a, rectangle_b)
78        }
79    }
80}