word_cloud/collision/
bb_collider.rs

1use quadtree_rs::{area::AreaBuilder, point::Point, Quadtree};
2
3use crate::geometry::{Rectangle, Vector};
4
5use super::CollisionStrategy;
6
7/// The default collision detection implemented with a QuadTree
8pub struct BoundingBoxCollider {
9    qt: Quadtree<u32, Rectangle>,
10    padding: u32,
11}
12
13impl BoundingBoxCollider {
14    /// Create a new BoundingBoxCollider instance.
15    ///
16    /// `max_width` is the maximum width of the surface detecting the collisions.
17    ///
18    /// `padding` is the spacing to use between rectangles.
19    pub fn new(max_width: u32, padding: u32) -> BoundingBoxCollider {
20        BoundingBoxCollider {
21            qt: Quadtree::<u32, Rectangle>::new(f32::sqrt(max_width as f32) as usize),
22            padding,
23        }
24    }
25}
26
27impl CollisionStrategy for BoundingBoxCollider {
28    fn collides(&self, pos: Vector, r: &Rectangle) -> bool {
29        let r = r.grow(2 * self.padding as isize).unwrap();
30
31        let region = AreaBuilder::default()
32            .anchor(Point { x: pos.0, y: pos.1 })
33            .dimensions((r.size().0, r.size().1))
34            .build()
35            .unwrap();
36
37        let query = self.qt.query(region);
38
39        query.count() != 0
40    }
41
42    fn add(&mut self, pos: Vector, r: Rectangle) {
43        let region = AreaBuilder::default()
44            .anchor(Point {
45                x: pos.0 + self.padding,
46                y: pos.1 + self.padding,
47            })
48            .dimensions((r.size().0, r.size().1))
49            .build()
50            .unwrap();
51
52        self.qt.insert(region, r);
53    }
54}
55
56#[cfg(test)]
57mod test {
58    use super::*;
59
60    #[test]
61    fn collide() {
62        let mut bbc = BoundingBoxCollider::new(50, 0);
63        bbc.add((0, 0), Rectangle::new(0, 0, 10, 5));
64        bbc.add((20, 0), Rectangle::new(20, 0, 10, 10));
65
66        assert!(!bbc.collides((15, 5), &Rectangle::new(0, 0, 5, 3)));
67        assert!(!bbc.collides((30, 5), &Rectangle::new(0, 0, 5, 3)));
68
69        assert!(bbc.collides((15, 0), &Rectangle::new(0, 0, 10, 10)));
70        assert!(bbc.collides((0, 0), &Rectangle::new(0, 0, 1, 1)));
71    }
72}