rg3d_core/
quadtree.rs

1use crate::{
2    algebra::Vector2,
3    math::Rect,
4    pool::{Handle, Pool},
5};
6use arrayvec::ArrayVec;
7
8pub enum QuadTreeNode<T> {
9    Leaf {
10        bounds: Rect<f32>,
11        ids: Vec<T>,
12    },
13    Branch {
14        bounds: Rect<f32>,
15        leaves: [Handle<QuadTreeNode<T>>; 4],
16    },
17}
18
19fn split_rect(rect: &Rect<f32>) -> [Rect<f32>; 4] {
20    let half_size = rect.size.scale(0.5);
21    [
22        Rect {
23            position: rect.position,
24            size: half_size,
25        },
26        Rect {
27            position: Vector2::new(rect.position.x + half_size.x, rect.position.y),
28            size: half_size,
29        },
30        Rect {
31            position: rect.position + half_size,
32            size: half_size,
33        },
34        Rect {
35            position: Vector2::new(rect.position.x, rect.position.y + half_size.y),
36            size: half_size,
37        },
38    ]
39}
40
41pub struct QuadTree<T> {
42    nodes: Pool<QuadTreeNode<T>>,
43    root: Handle<QuadTreeNode<T>>,
44    split_threshold: usize,
45}
46
47impl<T> Default for QuadTree<T> {
48    fn default() -> Self {
49        Self {
50            nodes: Default::default(),
51            root: Default::default(),
52            split_threshold: 16,
53        }
54    }
55}
56
57pub trait BoundsProvider {
58    type Id: Clone;
59
60    fn bounds(&self) -> Rect<f32>;
61
62    fn id(&self) -> Self::Id;
63}
64
65pub enum QuadTreeBuildError {
66    /// It means that given split threshold is too low for an algorithm to build quad tree.
67    /// Make it larger and try again. Also this might mean that your initial bounds are too small.
68    ReachedRecursionLimit,
69}
70
71#[derive(Clone)]
72struct Entry<I: Clone> {
73    id: I,
74    bounds: Rect<f32>,
75}
76
77fn build_recursive<I: Clone>(
78    nodes: &mut Pool<QuadTreeNode<I>>,
79    bounds: Rect<f32>,
80    entries: &[Entry<I>],
81    split_threshold: usize,
82    depth: usize,
83) -> Result<Handle<QuadTreeNode<I>>, QuadTreeBuildError> {
84    if depth >= 64 {
85        Err(QuadTreeBuildError::ReachedRecursionLimit)
86    } else if entries.len() <= split_threshold {
87        Ok(nodes.spawn(QuadTreeNode::Leaf {
88            bounds,
89            ids: entries.iter().map(|e| e.id.clone()).collect::<Vec<_>>(),
90        }))
91    } else {
92        let leaf_bounds = split_rect(&bounds);
93        let mut leaves = [Handle::NONE; 4];
94
95        for (leaf, &leaf_bounds) in leaves.iter_mut().zip(leaf_bounds.iter()) {
96            let leaf_entries = entries
97                .iter()
98                .filter_map(|e| {
99                    if leaf_bounds.intersects(e.bounds) {
100                        Some(e.clone())
101                    } else {
102                        None
103                    }
104                })
105                .collect::<Vec<_>>();
106
107            *leaf = build_recursive(
108                nodes,
109                leaf_bounds,
110                &leaf_entries,
111                split_threshold,
112                depth + 1,
113            )?;
114        }
115
116        Ok(nodes.spawn(QuadTreeNode::Branch { bounds, leaves }))
117    }
118}
119
120impl<I: Clone> QuadTree<I> {
121    pub fn new<T: BoundsProvider<Id = I>>(
122        root_bounds: Rect<f32>,
123        objects: impl Iterator<Item = T>,
124        split_threshold: usize,
125    ) -> Result<Self, QuadTreeBuildError> {
126        let entries = objects
127            .filter_map(|o| {
128                if root_bounds.intersects(o.bounds()) {
129                    Some(Entry {
130                        id: o.id(),
131                        bounds: o.bounds(),
132                    })
133                } else {
134                    None
135                }
136            })
137            .collect::<Vec<_>>();
138
139        let mut nodes = Pool::new();
140        let root = build_recursive(&mut nodes, root_bounds, &entries, split_threshold, 0)?;
141        Ok(Self {
142            nodes,
143            root,
144            split_threshold,
145        })
146    }
147
148    pub fn point_query<S: QueryStorage<Id = I>>(&self, point: Vector2<f32>, storage: &mut S) {
149        self.point_query_recursive(self.root, point, storage)
150    }
151
152    fn point_query_recursive<S: QueryStorage<Id = I>>(
153        &self,
154        node: Handle<QuadTreeNode<I>>,
155        point: Vector2<f32>,
156        storage: &mut S,
157    ) {
158        if node.is_some() {
159            match self.nodes.borrow(node) {
160                QuadTreeNode::Leaf { bounds, ids } => {
161                    if bounds.contains(point) {
162                        for id in ids {
163                            if !storage.try_push(id.clone()) {
164                                return;
165                            }
166                        }
167                    }
168                }
169                QuadTreeNode::Branch { bounds, leaves } => {
170                    if bounds.contains(point) {
171                        for &leaf in leaves {
172                            self.point_query_recursive(leaf, point, storage)
173                        }
174                    }
175                }
176            }
177        }
178    }
179
180    pub fn split_threshold(&self) -> usize {
181        self.split_threshold
182    }
183}
184
185pub trait QueryStorage {
186    type Id;
187
188    fn try_push(&mut self, id: Self::Id) -> bool;
189
190    /// Clears the storage.
191    fn clear(&mut self);
192}
193
194impl<I> QueryStorage for Vec<I> {
195    type Id = I;
196
197    fn try_push(&mut self, intersection: I) -> bool {
198        self.push(intersection);
199        true
200    }
201
202    fn clear(&mut self) {
203        self.clear()
204    }
205}
206
207impl<I, const CAP: usize> QueryStorage for ArrayVec<I, CAP> {
208    type Id = I;
209
210    fn try_push(&mut self, intersection: I) -> bool {
211        self.try_push(intersection).is_ok()
212    }
213
214    fn clear(&mut self) {
215        self.clear()
216    }
217}
218
219#[cfg(test)]
220mod test {
221    use crate::math::Rect;
222    use crate::quadtree::{BoundsProvider, QuadTree};
223
224    struct TestObject {
225        bounds: Rect<f32>,
226        id: usize,
227    }
228
229    impl BoundsProvider for &TestObject {
230        type Id = usize;
231
232        fn bounds(&self) -> Rect<f32> {
233            self.bounds
234        }
235
236        fn id(&self) -> Self::Id {
237            self.id
238        }
239    }
240
241    #[test]
242    fn test_quad_tree() {
243        let root_bounds = Rect::new(0.0, 0.0, 200.0, 200.0);
244        let objects = vec![
245            TestObject {
246                bounds: Rect::new(10.0, 10.0, 10.0, 10.0),
247                id: 0,
248            },
249            TestObject {
250                bounds: Rect::new(10.0, 10.0, 10.0, 10.0),
251                id: 1,
252            },
253        ];
254        // Infinite recursion prevention check (when there are multiple objects share same location).
255        assert!(QuadTree::new(root_bounds, objects.iter(), 1).is_err());
256
257        let objects = vec![
258            TestObject {
259                bounds: Rect::new(10.0, 10.0, 10.0, 10.0),
260                id: 0,
261            },
262            TestObject {
263                bounds: Rect::new(20.0, 20.0, 10.0, 10.0),
264                id: 1,
265            },
266        ];
267        assert!(QuadTree::new(root_bounds, objects.iter(), 1).is_ok());
268    }
269}