aabb_quadtree/
lib.rs

1#![deny(missing_docs)]
2
3//! A simple spacial partitioning data structure that
4//! allows fast queries for 2-dimensional objects.
5//!
6//! As the name implies, the tree is a mapping from
7//! axis-aligned-bounding-box => object.
8
9extern crate euclid;
10extern crate fnv;
11extern crate smallvec;
12
13use euclid::{TypedPoint2D, TypedRect, TypedSize2D};
14use fnv::FnvHashMap;
15use smallvec::{Array, SmallVec};
16use std::cmp::Ord;
17
18type Rect<S> = TypedRect<f32, S>;
19type Point<S> = TypedPoint2D<f32, S>;
20
21/// An object that has a bounding box.
22///
23/// Implementing this trait is not required, but can make
24/// insertions easier.
25pub trait Spatial<S> {
26    /// Returns the boudning box for the object.
27    fn aabb(&self) -> Rect<S>;
28}
29
30/// Used to determine if a query should keep going or not
31pub type QueryResult<B> = Result<(), B>;
32
33/// An ID unique to a single QuadTree.  This is the object
34/// that is returned from queries, and can be used to
35/// access the elements stored in the quad tree.
36///
37/// DO NOT use an ItemId on a quadtree unless the ItemId
38/// came from that tree.
39#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy, Debug)]
40pub struct ItemId(u32);
41
42#[derive(Debug, Clone)]
43struct QuadTreeConfig {
44    allow_duplicates: bool,
45    max_children: usize,
46    min_children: usize,
47    max_depth: usize,
48    epsilon: f32,
49}
50
51/// The main QuadTree structure.  Mainly supports
52/// inserting, removing, and querying objects in 3d space.
53#[derive(Clone)]
54pub struct QuadTree<T, S, A: Array<Item = (ItemId, Rect<S>)>> {
55    root: QuadNode<S, A>,
56    config: QuadTreeConfig,
57    id: u32,
58    elements: FnvHashMap<ItemId, (T, Rect<S>)>,
59}
60
61enum QuadNode<S, A: Array<Item = (ItemId, Rect<S>)>> {
62    Branch {
63        aabb: Rect<S>,
64        element_count: usize,
65        depth: usize,
66        in_all: SmallVec<A>,
67        children: [(Rect<S>, Box<QuadNode<S, A>>); 4],
68    },
69    Leaf {
70        aabb: Rect<S>,
71        depth: usize,
72        elements: SmallVec<A>,
73    },
74}
75
76impl<S, A: Array<Item = (ItemId, Rect<S>)>> Clone for QuadNode<S, A> {
77    fn clone(&self) -> QuadNode<S, A> {
78        match self {
79            &QuadNode::Branch {
80                ref aabb,
81                ref children,
82                ref in_all,
83                ref element_count,
84                ref depth,
85            } => {
86                let children = [
87                    children[0].clone(),
88                    children[1].clone(),
89                    children[2].clone(),
90                    children[3].clone(),
91                ];
92                QuadNode::Branch {
93                    aabb: aabb.clone(),
94                    children: children,
95                    in_all: in_all.clone(),
96                    element_count: element_count.clone(),
97                    depth: depth.clone(),
98                }
99            }
100            &QuadNode::Leaf {
101                ref aabb,
102                ref elements,
103                ref depth,
104            } => QuadNode::Leaf {
105                aabb: aabb.clone(),
106                elements: elements.clone(),
107                depth: depth.clone(),
108            },
109        }
110    }
111}
112
113impl<T, S, A: Array<Item = (ItemId, Rect<S>)>> QuadTree<T, S, A> {
114    /// Constructs a new QuadTree with customizable options.
115    ///
116    /// * `size`: the enclosing space for the quad-tree.
117    /// * `allow_duplicates`: if false, the quadtree will
118    /// remove objects that have the same bounding box.
119    /// * `min_children`: the minimum amount of children
120    /// that a tree node will have. * `max_children`:
121    /// the maximum amount of children that a tree node
122    /// will have before it gets split. * `max_depth`:
123    /// the maximum depth that the tree can grow before it
124    /// stops.
125    pub fn new(
126        size: Rect<S>,
127        allow_duplicates: bool,
128        min_children: usize,
129        max_children: usize,
130        max_depth: usize,
131        size_hint: usize,
132    ) -> QuadTree<T, S, A> {
133        QuadTree {
134            root: QuadNode::Leaf {
135                aabb: size,
136                elements: SmallVec::new(),
137                depth: 0,
138            },
139            config: QuadTreeConfig {
140                allow_duplicates: allow_duplicates,
141                max_children: max_children,
142                min_children: min_children,
143                max_depth: max_depth,
144                epsilon: 0.0001,
145            },
146            id: 0,
147            elements: std::collections::HashMap::with_capacity_and_hasher(
148                size_hint,
149                Default::default(),
150            ),
151        }
152    }
153
154    /// Constructs a new QuadTree with customizable options.
155    ///
156    /// * `size`: the enclosing space for the quad-tree.
157    /// ### Defauts
158    /// * `allow_duplicates`: true
159    /// * `min_children`: 4
160    /// * `max_children`: 16
161    /// * `max_depth`: 8
162    pub fn default(size: Rect<S>, size_hint: usize) -> QuadTree<T, S, A> {
163        QuadTree::new(size, true, 4, 16, 8, size_hint)
164    }
165
166    /// Inserts an element with the provided bounding box.
167    pub fn insert_with_box(&mut self, t: T, aabb: Rect<S>) -> Option<ItemId> {
168        debug_assert!(self.bounding_box().contains(&aabb.origin));
169        debug_assert!(self.bounding_box().contains(&aabb.bottom_right()));
170
171        let &mut QuadTree {
172            ref mut root,
173            ref config,
174            ref mut id,
175            ref mut elements,
176        } = self;
177
178        let item_id = ItemId(*id);
179        *id += 1;
180
181        if root.insert(item_id, aabb, config) {
182            elements.insert(item_id, (t, aabb));
183            return Some(item_id);
184        } else {
185            return None;
186        }
187    }
188
189    /// Returns an ItemId for the first element that was
190    /// inserted into the tree.
191    pub fn first(&self) -> Option<ItemId> {
192        self.elements.iter().next().map(|(id, _)| *id)
193    }
194
195    /// Inserts an element into the tree.
196    pub fn insert(&mut self, t: T) -> Option<ItemId>
197    where
198        T: Spatial<S>,
199    {
200        let b = t.aabb();
201        self.insert_with_box(t, b)
202    }
203
204    /// Retrieves an element by looking it up from the
205    /// ItemId.
206    pub fn get(&self, id: ItemId) -> Option<&T> {
207        self.elements.get(&id).map(|&(ref a, _)| a)
208    }
209
210    /// Returns an iterator of (element, bounding-box, id)
211    /// for each element whose bounding box intersects
212    /// with `bounding_box`.
213    pub fn query(&self, bounding_box: Rect<S>) -> SmallVec<[(&T, Rect<S>, ItemId); 3]>
214    where
215        T: ::std::fmt::Debug,
216    {
217        let mut out: SmallVec<[(_, _, _); 3]> = Default::default();
218        let _ = self.root
219            .query::<(), _>(bounding_box, &self.config, &mut |id, bb| {
220                out.push((&self.elements.get(&id).unwrap().0, bb, id));
221                Ok(())
222            });
223        out.sort_by_key(|&(_, _, id)| id);
224        out.dedup_by_key(|&mut (_, _, id)| id);
225        out
226    }
227
228    /// Executes 'on_find' for every element found in the
229    /// bounding-box
230    pub fn custom_query<'a, B, F>(&'a self, query_aabb: Rect<S>, on_find: &mut F) -> QueryResult<B>
231    where
232        F: FnMut(ItemId, Rect<S>) -> QueryResult<B>,
233    {
234        self.root.query(query_aabb, &self.config, on_find)
235    }
236
237    /// Attempts to remove the item with id `item_id` from
238    /// the tree.  If that item was present, it returns
239    /// a tuple of (element, bounding-box)
240    pub fn remove(&mut self, item_id: ItemId) -> Option<(T, Rect<S>)> {
241        match self.elements.remove(&item_id) {
242            Some((item, aabb)) => {
243                self.root.remove(item_id, aabb, &self.config);
244                Some((item, aabb))
245            }
246            None => None,
247        }
248    }
249
250    /// Returns an iterator over all the items in the tree.
251    pub fn iter(&self) -> ::std::collections::hash_map::Iter<ItemId, (T, Rect<S>)> {
252        self.elements.iter()
253    }
254
255    /// Calls `f` repeatedly for every node in the tree
256    /// with these arguments
257    ///
258    /// * `&Rect`: The boudning box of that tree node
259    /// * `usize`: The current depth
260    /// * `bool`: True if the node is a leaf-node, False if
261    /// the node is a branch node.
262    pub fn inspect<F: FnMut(&Rect<S>, usize, bool)>(&self, mut f: F) {
263        self.root.inspect(&mut f);
264    }
265
266    /// Returns the number of elements in the tree
267    pub fn len(&self) -> usize {
268        self.elements.len()
269    }
270
271    /// Returns true if the tree is empty.
272    pub fn is_empty(&self) -> bool {
273        self.elements.is_empty()
274    }
275
276    /// Returns the enclosing bounding-box for the entire
277    /// tree.
278    pub fn bounding_box(&self) -> Rect<S> {
279        self.root.bounding_box()
280    }
281}
282
283impl<S, A: Array<Item = (ItemId, Rect<S>)>> QuadNode<S, A> {
284    fn bounding_box(&self) -> Rect<S> {
285        match self {
286            &QuadNode::Branch { ref aabb, .. } => aabb.clone(),
287            &QuadNode::Leaf { ref aabb, .. } => aabb.clone(),
288        }
289    }
290
291    fn new_leaf(aabb: Rect<S>, depth: usize) -> QuadNode<S, A> {
292        QuadNode::Leaf {
293            aabb: aabb,
294            elements: SmallVec::new(),
295            depth: depth,
296        }
297    }
298
299    fn inspect<F: FnMut(&Rect<S>, usize, bool)>(&self, f: &mut F) {
300        match self {
301            &QuadNode::Branch {
302                depth,
303                ref aabb,
304                ref children,
305                ..
306            } => {
307                f(aabb, depth, false);
308                for child in children {
309                    child.1.inspect(f);
310                }
311            }
312            &QuadNode::Leaf {
313                depth, ref aabb, ..
314            } => {
315                f(aabb, depth, true);
316            }
317        }
318    }
319
320    fn insert(&mut self, item_id: ItemId, item_aabb: Rect<S>, config: &QuadTreeConfig) -> bool {
321        let mut into = None;
322        let mut did_insert = false;
323        match self {
324            &mut QuadNode::Branch {
325                ref aabb,
326                ref mut in_all,
327                ref mut children,
328                ref mut element_count,
329                ..
330            } => {
331                if item_aabb.contains(&midpoint(*aabb)) {
332                    // Only insert if there isn't another item with a very
333                    // similar aabb.
334                    if config.allow_duplicates
335                        || !in_all
336                            .iter()
337                            .any(|&(_, e_bb)| close_to_rect(e_bb, item_aabb, config.epsilon))
338                    {
339                        in_all.push((item_id, item_aabb));
340                        did_insert = true;
341                        *element_count += 1;
342                    }
343                } else {
344                    for &mut (aabb, ref mut child) in children {
345                        if my_intersects(aabb, item_aabb)
346                            || close_to_rect(aabb, item_aabb, config.epsilon)
347                        {
348                            if child.insert(item_id, item_aabb, config) {
349                                *element_count += 1;
350                                did_insert = true;
351                            }
352                        }
353                    }
354                }
355            }
356
357            &mut QuadNode::Leaf {
358                aabb,
359                ref mut elements,
360                ref depth,
361            } => {
362                if elements.len() == config.max_children && *depth != config.max_depth {
363                    // STEAL ALL THE CHILDREN MUAHAHAHAHA
364                    let mut extracted_children = SmallVec::new();
365                    ::std::mem::swap(&mut extracted_children, elements);
366                    extracted_children.push((item_id, item_aabb));
367                    did_insert = true;
368
369                    let split = split_quad(aabb);
370                    into = Some((
371                        extracted_children,
372                        QuadNode::Branch {
373                            aabb: aabb,
374                            in_all: SmallVec::new(),
375                            children: [
376                                (split[0], Box::new(QuadNode::new_leaf(split[0], depth + 1))),
377                                (split[1], Box::new(QuadNode::new_leaf(split[1], depth + 1))),
378                                (split[2], Box::new(QuadNode::new_leaf(split[2], depth + 1))),
379                                (split[3], Box::new(QuadNode::new_leaf(split[3], depth + 1))),
380                            ],
381                            element_count: 0,
382                            depth: *depth,
383                        },
384                    ));
385                } else {
386                    if config.allow_duplicates
387                        || !elements
388                            .iter()
389                            .any(|&(_, e_bb)| close_to_rect(e_bb, item_aabb, config.epsilon))
390                    {
391                        elements.push((item_id, item_aabb));
392                        did_insert = true;
393                    }
394                }
395            }
396        }
397
398        // If we transitioned from a leaf node to a branch node, we
399        // need to update ourself and re-add all the children that
400        // we used to have
401        // in our this leaf into our new leaves.
402        if let Some((extracted_children, new_node)) = into {
403            *self = new_node;
404            for (child_id, child_aabb) in extracted_children {
405                self.insert(child_id, child_aabb, config);
406            }
407        }
408        if !did_insert {
409            panic!(
410                "didn't insert {:?} into {:?}",
411                item_aabb,
412                self.bounding_box()
413            );
414        }
415        did_insert
416    }
417
418    fn remove(&mut self, item_id: ItemId, item_aabb: Rect<S>, config: &QuadTreeConfig) -> bool {
419        fn remove_from<S, A: Array<Item = (ItemId, Rect<S>)>>(
420            v: &mut SmallVec<A>,
421            item: ItemId,
422        ) -> bool {
423            if let Some(index) = v.iter().position(|a| a.0 == item) {
424                v.swap_remove(index);
425                true
426            } else {
427                false
428            }
429        }
430
431        let mut compact = None;
432        let removed = match self {
433            &mut QuadNode::Branch {
434                ref depth,
435                ref aabb,
436                ref mut in_all,
437                ref mut children,
438                ref mut element_count,
439                ..
440            } => {
441                let mut did_remove = false;
442
443                if item_aabb.contains(&midpoint(*aabb)) {
444                    did_remove = remove_from(in_all, item_id);
445                } else {
446                    for &mut (child_aabb, ref mut child_tree) in children {
447                        if my_intersects(child_aabb, item_aabb)
448                            || close_to_rect(child_aabb, item_aabb, config.epsilon)
449                        {
450                            did_remove |= child_tree.remove(item_id, item_aabb, config);
451                        }
452                    }
453                }
454
455                if did_remove {
456                    *element_count -= 1;
457                    if *element_count < config.min_children {
458                        compact = Some((*element_count, *aabb, *depth));
459                    }
460                }
461                did_remove
462            }
463
464            &mut QuadNode::Leaf {
465                ref mut elements, ..
466            } => remove_from(elements, item_id),
467        };
468
469        if let Some((size, aabb, depth)) = compact {
470            let mut elements: SmallVec<A> = SmallVec::with_capacity(size);
471            self.query::<(), _>(aabb, config, &mut |id, bb| {
472                elements.push((id, bb));
473                Ok(())
474            }).ok();
475            elements.sort_by(|&(id1, _), &(ref id2, _)| id1.cmp(id2));
476            elements.dedup();
477            *self = QuadNode::Leaf {
478                aabb: aabb,
479                elements: elements,
480                depth: depth,
481            };
482        }
483        removed
484    }
485
486    fn query<B, F>(
487        &self,
488        query_aabb: Rect<S>,
489        config: &QuadTreeConfig,
490        on_find: &mut F,
491    ) -> QueryResult<B>
492    where
493        F: FnMut(ItemId, Rect<S>) -> QueryResult<B>,
494    {
495        fn match_all<B, S, F, A: Array<Item = (ItemId, Rect<S>)>>(
496            elements: &SmallVec<A>,
497            query_aabb: Rect<S>,
498            on_find: &mut F,
499            config: &QuadTreeConfig,
500        ) -> QueryResult<B>
501        where
502            F: FnMut(ItemId, Rect<S>) -> QueryResult<B>,
503        {
504            for &(child_id, child_aabb) in elements {
505                if my_intersects(query_aabb, child_aabb)
506                    || close_to_rect(query_aabb, child_aabb, config.epsilon)
507                {
508                    on_find(child_id, child_aabb)?;
509                }
510            }
511            Ok(())
512        }
513
514        match self {
515            &QuadNode::Branch {
516                ref in_all,
517                ref children,
518                ..
519            } => {
520                match_all(in_all, query_aabb, on_find, config)?;
521
522                for &(child_aabb, ref child_tree) in children {
523                    if my_intersects(query_aabb, child_aabb) {
524                        child_tree.query(query_aabb, config, on_find)?;
525                    }
526                }
527            }
528            &QuadNode::Leaf { ref elements, .. } => {
529                match_all(elements, query_aabb, on_find, config)?
530            }
531        }
532        Ok(())
533    }
534}
535
536impl<S> Spatial<S> for Rect<S> {
537    fn aabb(&self) -> Rect<S> {
538        *self
539    }
540}
541
542impl<S> Spatial<S> for Point<S> {
543    fn aabb(&self) -> Rect<S> {
544        Rect::new(*self, TypedSize2D::new(0.0, 0.0))
545    }
546}
547
548fn midpoint<S>(rect: Rect<S>) -> Point<S> {
549    let origin = rect.origin;
550    let half = rect.size.to_vector() / 2.0;
551    origin + half
552}
553
554fn my_intersects<S>(a: Rect<S>, b: Rect<S>) -> bool {
555    a.intersects(&b) || a.contains(&b.origin) || a.contains(&b.bottom_right())
556}
557
558fn split_quad<S>(rect: Rect<S>) -> [Rect<S>; 4] {
559    use euclid::vec2;
560    let origin = rect.origin;
561    let half = rect.size / 2.0;
562
563    [
564        Rect::new(origin, half),
565        Rect::new(origin + vec2(half.width, 0.0), half),
566        Rect::new(origin + vec2(0.0, half.height), half),
567        Rect::new(origin + vec2(half.width, half.height), half),
568    ]
569}
570
571fn close_to_point<S>(a: Point<S>, b: Point<S>, epsilon: f32) -> bool {
572    (a.x - b.x).abs() < epsilon && (a.y - b.y).abs() < epsilon
573}
574fn close_to_rect<S>(a: Rect<S>, b: Rect<S>, epsilon: f32) -> bool {
575    close_to_point(a.origin, b.origin, epsilon)
576        && close_to_point(a.bottom_right(), b.bottom_right(), epsilon)
577}
578
579#[test]
580fn weird_case() {
581    use euclid::*;
582    let bb = Rect::new(point2(0.0, 0.0), vec2(10.0, 10.0).to_size());
583    let query = Rect::new(point2(20.0, 0.0), vec2(1.0, 0.0).to_size());
584    assert!(!my_intersects(bb, query));
585}
586
587#[test]
588fn test_boundary_conditions() {
589    use euclid::*;
590
591    let total = Rect::new(point2(0.0, 0.0), vec2(10.0, 10.0).to_size());
592    let quads = split_quad(total);
593    let config = QuadTreeConfig {
594        allow_duplicates: true,
595        max_children: 200,
596        min_children: 0,
597        max_depth: 5,
598        epsilon: 0.001,
599    };
600
601    let mut branch: QuadNode<_, [(ItemId, Rect<_>); 32]> = QuadNode::Branch {
602        aabb: total,
603        in_all: SmallVec::new(),
604        element_count: 0,
605        depth: 1,
606        children: [
607            (
608                quads[0],
609                Box::new(QuadNode::Leaf {
610                    aabb: quads[0],
611                    elements: SmallVec::new(),
612                    depth: 2,
613                }),
614            ),
615            (
616                quads[1],
617                Box::new(QuadNode::Leaf {
618                    aabb: quads[1],
619                    elements: SmallVec::new(),
620                    depth: 2,
621                }),
622            ),
623            (
624                quads[2],
625                Box::new(QuadNode::Leaf {
626                    aabb: quads[2],
627                    elements: SmallVec::new(),
628                    depth: 2,
629                }),
630            ),
631            (
632                quads[3],
633                Box::new(QuadNode::Leaf {
634                    aabb: quads[3],
635                    elements: SmallVec::new(),
636                    depth: 2,
637                }),
638            ),
639        ],
640    };
641
642    // Top left corner
643    assert!(branch.insert(
644        ItemId(0),
645        Rect::new(point2(0.0, 0.0), vec2(0.0, 0.0).to_size()),
646        &config
647    ));
648    // Middle
649    assert!(branch.insert(
650        ItemId(0),
651        Rect::new(point2(5.0, 5.0), vec2(0.0, 0.0).to_size()),
652        &config
653    ));
654}
655
656impl<T: ::std::fmt::Debug, S, A: Array<Item = (ItemId, Rect<S>)>> ::std::fmt::Debug
657    for QuadTree<T, S, A>
658{
659    fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
660        formatter
661            .debug_struct("QuadTree")
662            .field("root", &self.root)
663            .field("config", &self.config)
664            .field("id", &self.id)
665            .field("elements", &self.elements)
666            .finish()
667    }
668}
669
670impl<S, A: Array<Item = (ItemId, Rect<S>)>> ::std::fmt::Debug for QuadNode<S, A> {
671    fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
672        match self {
673            &QuadNode::Branch {
674                ref aabb,
675                ref children,
676                ref in_all,
677                ref element_count,
678                ref depth,
679            } => formatter
680                .debug_struct("QuadNode")
681                .field("aabb", aabb)
682                .field("children", children)
683                .field("in_all", in_all)
684                .field("element_count", element_count)
685                .field("depth", depth)
686                .finish(),
687
688            &QuadNode::Leaf {
689                ref aabb,
690                ref elements,
691                ref depth,
692            } => formatter
693                .debug_struct("QuadNode")
694                .field("aabb", aabb)
695                .field("elements", elements)
696                .field("depth", depth)
697                .finish(),
698        }
699    }
700}