1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
use crate::intersections::IntersectsWith;
use crate::quadtree::aabb::AABB;
use crate::quadtree::error::InsertError;
use crate::quadtree::free_list;
use crate::quadtree::free_list::{FreeList, IndexType};
use crate::quadtree::node::Node;
use crate::quadtree::node_data::{NodeData, NodeIndexType};
use crate::quadtree::node_info::NodeInfo;
use crate::quadtree::node_list::NodeList;
use crate::quadtree::quad_rect::QuadRect;
use crate::quadtree::quadrants::Quadrants;
pub use crate::quadtree::quadtree_element::{ElementIdType, QuadTreeElement};
use crate::types::HashSet;
use smallvec::SmallVec;

// TODO: Add range query: Query using intersect_aabb() or intersect_generic()

/// Represents an element node in the quadtree.
///
/// # Remarks
/// An element (`QuadTreeElement`) is only inserted once to the quadtree no matter how many
/// cells it occupies. However, for each cell it occupies, an "element node" (`QuadTreeElementNode`)
/// is inserted which indexes that element.
#[derive(Debug, PartialEq, Eq, Default, Copy, Clone)]
struct QuadTreeElementNode {
    /// Points to the next element in the leaf node. A value of `free_list::SENTINEL`
    /// indicates the end of the list.
    next: free_list::IndexType,
    /// Stores the element index.
    element_idx: free_list::IndexType,
}

/// A QuadTree implementation as described in [Efficient Quadtrees](https://stackoverflow.com/a/48330314/195651).
///
/// # Remarks
/// This tree uses integral coordinates only in order to speed up box-box intersection tests.
pub struct QuadTree<ElementId = u32>
where
    ElementId: ElementIdType,
{
    /// Stores all the IDs fo the elements in the quadtree.
    /// An element is only inserted once to the quadtree no matter how many cells it occupies.
    element_ids: FreeList<ElementId>,
    /// Stores all the rectangles of the elements in the quadtree.
    /// An element is only inserted once to the quadtree no matter how many cells it occupies.
    element_rects: FreeList<AABB>,
    /// Stores all the element nodes in the quadtree.
    /// For each cell occupied by a `QuadTreeElement`, we store
    /// a `QuadTreeElementNode`.
    element_nodes: FreeList<QuadTreeElementNode>,
    /// Stores all the nodes in the quadtree. The first node in this
    /// sequence is always the root.
    nodes: Vec<Node>,
    /// Stores the quadtree extents.
    root_rect: QuadRect,
    /// Stores the first free node in the quadtree to be reclaimed as 4
    /// contiguous nodes at once. A value of `free_list::SENTINEL` indicates that the free
    /// list is empty, at which point we simply insert 4 nodes to the
    /// back of the nodes array.
    free_node: free_list::IndexType,
    /// Stores the maximum depth allowed for the quadtree.
    max_depth: u32,
    /// Stores the maximum number of elements allowed before a node splits.
    max_num_elements: u32,
    /// We use this value to determine whether a node can be split.
    smallest_cell_size: u32,
}

impl<ElementId> QuadTree<ElementId>
where
    ElementId: ElementIdType,
{
    pub fn default() -> Self {
        Self::new(QuadRect::default(), 8, 16, 1)
    }

    pub fn new(
        root_rect: QuadRect,
        max_depth: u32,
        max_num_elements: u32,
        smallest_cell_size: u32,
    ) -> Self {
        assert!(max_num_elements > 0);
        assert!(smallest_cell_size > 0);
        Self {
            element_ids: FreeList::default(),
            element_rects: FreeList::default(),
            element_nodes: FreeList::default(),
            nodes: vec![Node::default()],
            root_rect,
            free_node: free_list::SENTINEL,
            max_depth,
            max_num_elements,
            smallest_cell_size,
        }
    }

    pub fn insert(&mut self, element: QuadTreeElement<ElementId>) -> Result<(), InsertError> {
        let element_coords = &element.rect;
        if !self.root_rect.contains(element_coords) {
            return Err(InsertError::OutOfBounds);
        }

        let max_num_elements = self.max_num_elements;

        // Insert the actual element.
        let element_idx = self.element_ids.insert(element.id);
        let element_rect_idx = self.element_rects.insert(element.rect);
        debug_assert_eq!(element_idx, element_rect_idx);

        let mut to_process: SmallVec<[NodeData; 128]> =
            smallvec::smallvec![self.get_root_node_data()];

        while !to_process.is_empty() {
            let node_data = to_process.pop().unwrap();

            // Find the leaves
            let mut leaves = self.find_leaves_aabb(node_data, element_coords);

            while !leaves.is_empty() {
                let leaf = leaves.pop_back();

                let (element_count, first_child_or_element) = {
                    let node = &self.nodes[leaf.index as usize];
                    debug_assert!(node.is_leaf());
                    (node.element_count, node.first_child_or_element)
                };

                let can_split = leaf.can_split_further(self.smallest_cell_size, self.max_depth);
                let node_is_full = element_count >= max_num_elements;

                let must_store_element = !node_is_full || !can_split;
                if must_store_element {
                    // This leaf takes the element reference without further splitting.
                    let element_node_idx = self.element_nodes.insert(QuadTreeElementNode {
                        element_idx,
                        next: first_child_or_element,
                    });
                    let node = &mut self.nodes[leaf.index as usize];
                    node.first_child_or_element = element_node_idx;
                    node.element_count += 1;
                } else {
                    // At this point we have to split the current node.
                    // We push the leaf back onto the stack in order to try to
                    // find a better insertion candidate from there.
                    self.distribute_elements_to_child_nodes(&leaf);
                    to_process.push(leaf);
                }
            }
        }

        Ok(())
    }

    /// Splits the specified [`parent`] node into four and distributes its
    /// elements onto the newly created childs.
    fn distribute_elements_to_child_nodes(&mut self, parent: &NodeData) {
        let first_child_index = self.ensure_child_nodes_exist();

        let node = &mut self.nodes[parent.index as usize];
        let mut element_node_index = node.get_first_element_node_index();
        node.make_branch(first_child_index);

        let mx = parent.crect.center_x;
        let my = parent.crect.center_y;

        // For each element in the list ...
        while element_node_index != free_list::SENTINEL {
            let element_node = unsafe { *self.element_nodes.at(element_node_index) };
            let element = unsafe { *self.element_rects.at(element_node.element_idx) };

            self.assign_element_to_child_nodes(
                mx,
                my,
                first_child_index,
                element_node.element_idx,
                &element,
            );

            // The element was assigned to the child nodes - the former node
            // can be removed (since the former leaf doesn't exist anymore).
            self.element_nodes.erase(element_node_index);

            element_node_index = element_node.next;
        }
    }

    /// Recycles child nodes from the free list or creates
    /// new child nodes if needed.
    fn ensure_child_nodes_exist(&mut self) -> u32 {
        if self.free_node == free_list::SENTINEL {
            let node_index = self.nodes.len() as IndexType;
            for _ in 0..4 {
                self.nodes.push(Node::default());
            }
            node_index
        } else {
            let node_index = self.free_node;
            let next_free_node = self.nodes[node_index as usize].first_child_or_element;
            self.nodes[node_index as usize] = Node::default();
            self.free_node = next_free_node;
            node_index
        }
    }

    /// Assigns an element to the child nodes starting at `first_child_index`.
    ///
    /// # Params
    /// * [`mx`] - The center X coordinate of the parent node.
    /// * [`my`] - The center Y coordinate of the parent node.
    /// * [`first_child_index`] - The index of the first child node.
    /// * [`element_index`] - The index of the element.
    /// * [`element`] - The element data.
    fn assign_element_to_child_nodes(
        &mut self,
        mx: i32,
        my: i32,
        first_child_index: free_list::IndexType,
        element_index: free_list::IndexType,
        element_rect: &AABB,
    ) {
        let insert_top = element_rect.tl.y <= my;
        let insert_bottom = element_rect.br.y > my;
        let insert_left = element_rect.tl.x <= mx;
        let insert_right = element_rect.br.x > mx;

        if insert_top & insert_left {
            self.insert_element_in_child_node(first_child_index + 0, element_index);
        }
        if insert_top & insert_right {
            self.insert_element_in_child_node(first_child_index + 1, element_index);
        }
        if insert_bottom & insert_left {
            self.insert_element_in_child_node(first_child_index + 2, element_index);
        }
        if insert_bottom & insert_right {
            self.insert_element_in_child_node(first_child_index + 3, element_index);
        }
    }

    fn insert_element_in_child_node(&mut self, child_index: u32, element: free_list::IndexType) {
        let node = &mut self.nodes[child_index as usize];
        let element_node_index = self.element_nodes.insert(QuadTreeElementNode {
            element_idx: element,
            next: node.first_child_or_element,
        });
        node.first_child_or_element = element_node_index;
        node.element_count += 1;
    }

    /// Removes the specified element.
    ///
    /// # Remarks
    /// The element is located using its bounding box and identified using the ID.
    /// Because of that, the bounding box of the element must not change until is was
    /// removed from the tree.
    ///
    /// # Arguments
    /// * [`element`] - The element to remove.
    pub fn remove(&mut self, element: &QuadTreeElement<ElementId>) -> bool {
        // Find the leaves containing the node.
        let element_coords = &element.rect;
        let root = self.get_root_node_data();

        // The index of the element (if it was found).
        let mut found_element_idx = free_list::SENTINEL;

        let mut leaves = self.find_leaves_aabb(root, element_coords);
        while !leaves.is_empty() {
            let leaf = leaves.pop_back();
            let leaf_node_data = self.nodes[leaf.index as usize];

            // The user may try to remove an element that was not in the tree (anymore).
            if leaf_node_data.element_count == 0 {
                continue;
            }

            // Used for debug assertion.
            let mut element_found = false;

            // Find the element in question.
            let mut element_node_idx = leaf_node_data.first_child_or_element;
            let mut prev_element_node_idx = element_node_idx;
            let mut new_first_child_or_element = element_node_idx;

            while element_node_idx != free_list::SENTINEL {
                let elem_node = *unsafe { self.element_nodes.at(element_node_idx) };
                let elem_id = unsafe { self.element_ids.at(elem_node.element_idx) };

                if *elem_id == element.id {
                    debug_assert!(!element_found);
                    element_found = true;

                    // If the element to be deleted is the first element,
                    // we need to update the leaf.
                    if leaf_node_data.first_child_or_element == element_node_idx {
                        new_first_child_or_element = elem_node.next;
                    }

                    // Update the previous node if it exists.
                    if element_node_idx != prev_element_node_idx {
                        unsafe { self.element_nodes.at_mut(prev_element_node_idx) }.next =
                            elem_node.next;
                    }

                    // Remove the reference from this leaf and
                    // keep track of the element index in the list.
                    self.element_nodes.erase(element_node_idx);
                    debug_assert!(
                        found_element_idx == free_list::SENTINEL
                            || found_element_idx == elem_node.element_idx
                    );
                    found_element_idx = elem_node.element_idx;
                }

                prev_element_node_idx = element_node_idx;
                element_node_idx = elem_node.next;

                // We assume that a user never inserts the same element
                // twice, therefore there is no need to visit the other
                // elements of this node if we found the correct one.
                //
                // To assert that elements are only inserted once (per node),
                // we allow further iteration during debugging.
                #[cfg(not(debug_assertions))]
                if element_found {
                    break;
                }
            }

            // Update the leaf node itself.
            let node = &mut self.nodes[leaf.index as usize];
            node.first_child_or_element = new_first_child_or_element;

            // The user may try to remove an element that was not in the tree (anymore).
            if element_found {
                debug_assert!(node.element_count > 0);
                node.element_count -= 1;
            }
        }

        if found_element_idx != free_list::SENTINEL {
            self.element_ids.erase(found_element_idx);
            self.element_rects.erase(found_element_idx);
            true
        } else {
            false
        }
    }

    // TODO: Prefer specialization, see https://github.com/rust-lang/rust/issues/31844
    fn find_leaves_aabb(&self, root: NodeData, rect: &AABB) -> NodeList {
        let mut leaves = NodeList::default(); // TODO: extract / pool?
        let mut to_process = NodeList::default(); // TODO: measure max size - back by SmallVec?
        to_process.push_back(root);

        while to_process.len() > 0 {
            let nd = to_process.pop_back();

            // If this node is a leaf, insert it to the list.
            if self.nodes[nd.index as usize].is_leaf() {
                leaves.push_back(nd);
                continue;
            }

            let fc = self.nodes[nd.index as usize].get_first_child_node_index();

            // Otherwise push the children that intersect the rectangle.
            let quadrants = nd.crect.explore_quadrants_aabb(rect);
            Self::collect_relevant_quadrants(&mut to_process, nd, fc, quadrants)
        }

        leaves
    }

    // TODO: Prefer specialization, see https://github.com/rust-lang/rust/issues/31844
    fn find_leaves_generic<T>(&self, root: NodeData, element: &T) -> NodeList
    where
        T: IntersectsWith<AABB>,
    {
        let mut leaves = NodeList::default(); // TODO: extract / pool?
        let mut to_process = NodeList::default(); // TODO: measure max size - back by SmallVec?
        to_process.push_back(root);

        while to_process.len() > 0 {
            let nd = to_process.pop_back();

            // If this node is a leaf, insert it to the list.
            if self.nodes[nd.index as usize].is_leaf() {
                leaves.push_back(nd);
                continue;
            }

            let fc = self.nodes[nd.index as usize].get_first_child_node_index();

            // Otherwise push the children that intersect the rectangle.
            let quadrants = nd.crect.explore_quadrants_generic(element);
            Self::collect_relevant_quadrants(&mut to_process, nd, fc, quadrants)
        }

        leaves
    }

    pub fn visit_leaves<F>(&self, mut visit: F)
    where
        F: FnMut(NodeInfo),
    {
        let mut to_process = NodeList::default(); // TODO: measure max size - back by SmallVec?
        to_process.push_back(self.get_root_node_data());

        while to_process.len() > 0 {
            let nd = to_process.pop_back();

            let node = &self.nodes[nd.index as usize];
            if node.is_leaf() {
                visit(NodeInfo::from(nd, node.element_count));
                continue;
            }

            let fc = self.nodes[nd.index as usize].get_first_child_node_index();
            Self::collect_relevant_quadrants(&mut to_process, nd, fc, Quadrants::all())
        }
    }

    fn collect_relevant_quadrants(
        to_process: &mut NodeList,
        nd: NodeData,
        first_child_id: u32,
        quadrants: Quadrants,
    ) {
        let mx = nd.crect.center_x;
        let my = nd.crect.center_y;
        let hx = nd.crect.width >> 1;
        let hy = nd.crect.height >> 1;

        let l = mx - hx;
        let t = my - hy;

        if quadrants.top_left {
            to_process.push_back(NodeData::new(
                l,
                t,
                hx,
                hy,
                first_child_id + 0,
                nd.depth + 1,
            ));
        }
        if quadrants.top_right {
            to_process.push_back(NodeData::new(
                mx,
                t,
                hx,
                hy,
                first_child_id + 1,
                nd.depth + 1,
            ));
        }
        if quadrants.bottom_left {
            to_process.push_back(NodeData::new(
                l,
                my,
                hx,
                hy,
                first_child_id + 2,
                nd.depth + 1,
            ));
        }
        if quadrants.bottom_right {
            to_process.push_back(NodeData::new(
                mx,
                my,
                hx,
                hy,
                first_child_id + 3,
                nd.depth + 1,
            ));
        }
    }

    /// Prunes unused child nodes from the tree.
    ///
    /// # Remarks
    /// The tree is never pruned automatically for performance reasons. Call
    /// this method after all elements were removed or updated.
    pub fn cleanup(&mut self) -> bool {
        // Only process the root if it is not a leaf.
        if self.nodes[0].is_leaf() {
            return false;
        }

        let mut tree_compacted = false;

        // Initialize the stack of nodes to be processed with the index of the root node.
        // TODO: revisit the small list size, check element count
        let mut to_process: SmallVec<[NodeIndexType; 128]> = smallvec::smallvec![0];

        while !to_process.is_empty() {
            let node_index = to_process.pop().unwrap();
            let first_child_index = self.nodes[node_index as usize].get_first_child_node_index();

            // Loop through the children.
            let mut num_empty_leaves = 0usize;
            for j in 0..4 {
                let child_index = first_child_index + j;
                let child = &self.nodes[child_index as usize];

                // TODO: Compact nodes when the number of elements in child is less than allowed maximum.

                // Increment empty leaf count if the child is an empty
                // leaf. Otherwise if the child is a branch, add it to
                // the stack to be processed in the next iteration.
                if child.is_empty() {
                    num_empty_leaves += 1; // TODO: Reverse, compare to zero
                } else if child.is_branch() {
                    to_process.push(child_index);
                }
            }

            // If all the children were empty leaves, remove them and
            // make this node the new empty leaf.
            if num_empty_leaves == 4 {
                // TODO: Reverse, compare to zero?
                // Push all 4 children to the free list.
                // (We don't change the indexes of the 2nd to 4th child because
                // child nodes are always processed together.)
                self.nodes[first_child_index as usize].first_child_or_element = self.free_node;
                self.free_node = first_child_index;

                // Make this node the new empty leaf.
                let node = &mut self.nodes[node_index as usize];
                node.make_empty_leaf();

                tree_compacted = true;
            }
        }

        tree_compacted
    }

    /// Counts the total number of references. This number should be at least
    /// the number of elements inserted; it will be higher if elements
    /// span multiple cells.
    #[allow(dead_code)]
    pub(crate) fn count_element_references(&self) -> usize {
        let mut to_process: SmallVec<[usize; 128]> = smallvec::smallvec![0];
        let mut count = 0usize;
        while !to_process.is_empty() {
            let index = to_process.pop().unwrap();
            let node = &self.nodes[index];
            if node.is_branch() {
                for j in 0..4 {
                    to_process.push((node.first_child_or_element + j) as usize);
                }
            } else {
                count += node.element_count as usize;
            }
        }

        debug_assert!(count >= self.element_ids.debug_len());
        debug_assert!(count >= self.element_rects.debug_len());
        count
    }

    #[inline]
    fn get_root_node_data(&self) -> NodeData {
        NodeData::new_from_root(&self.root_rect)
    }

    /// Returns the set of IDs that occupy space within the
    /// specified bounding box.
    ///
    /// # Arguments
    /// * [`rect`] - The rectangle to test for.
    #[inline]
    pub fn intersect_aabb(&self, rect: &AABB) -> HashSet<ElementId> {
        let root = self.get_root_node_data();
        let leaves = self.find_leaves_aabb(root, rect);
        let capacity = leaves.len() * self.max_num_elements as usize;
        let mut node_set = HashSet::with_capacity(capacity);
        self.intersect_from_leaves(rect, leaves, |id| {
            node_set.insert(id);
        });
        node_set
    }

    /// Calls a function for each ID that occupies space within the
    /// specified bounding box. The function may be called multiple
    /// times for the same ID.
    ///
    /// # Arguments
    /// * [`rect`] - The rectangle to test for.
    /// * [`candidate_fn`] - The function called for each candidate element's ID.
    #[inline]
    pub fn intersect_aabb_fn<F>(&self, rect: &AABB, candidate_fn: F)
    where
        F: FnMut(ElementId),
    {
        let root = self.get_root_node_data();
        let leaves = self.find_leaves_aabb(root, rect);
        self.intersect_from_leaves(rect, leaves, candidate_fn);
    }

    /// Returns the set of IDs that occupy space within the
    /// specified bounding box.
    ///
    /// # Arguments
    /// * [`element`] - The element to test for.
    #[inline]
    pub fn intersect_generic<T>(&self, element: &T) -> HashSet<ElementId>
    where
        T: IntersectsWith<AABB>,
    {
        let root = self.get_root_node_data();
        let leaves = self.find_leaves_generic(root, element);
        let capacity = leaves.len() * self.max_num_elements as usize;
        let mut node_set = HashSet::with_capacity(capacity);
        self.intersect_from_leaves(element, leaves, |id| {
            node_set.insert(id);
        });
        node_set
    }

    /// Calls a function for each ID that occupies space within the
    /// specified bounding box. The function may be called multiple
    /// times for the same ID.
    ///
    /// # Arguments
    /// * [`element`] - The element to test for.
    /// * [`candidate_fn`] - The function called for each candidate element's ID.
    #[inline]
    pub fn intersect_generic_fn<T, F>(&self, element: &T, candidate_fn: F)
    where
        T: IntersectsWith<AABB>,
        F: FnMut(ElementId),
    {
        let root = self.get_root_node_data();
        let leaves = self.find_leaves_generic(root, element);
        self.intersect_from_leaves(element, leaves, candidate_fn);
    }

    fn intersect_from_leaves<T, F>(&self, rect: &T, mut leaves: NodeList, mut candidate_fn: F)
    where
        T: IntersectsWith<AABB>,
        F: FnMut(ElementId),
    {
        while !leaves.is_empty() {
            let leaf_data = leaves.pop_back();
            let leaf = self.nodes[leaf_data.index as usize];
            debug_assert!(leaf.is_leaf());

            let mut elem_node_idx = leaf.first_child_or_element;
            while elem_node_idx != free_list::SENTINEL {
                let elem_node = unsafe { self.element_nodes.at(elem_node_idx) };
                let elem_rect = unsafe { self.element_rects.at(elem_node.element_idx) };

                // Depending on the size of the quadrant, the candidate element
                // might still not be covered by the search rectangle.
                if rect.intersects_with(&elem_rect) {
                    let elem_id = *unsafe { self.element_ids.at(elem_node.element_idx) };
                    candidate_fn(elem_id);
                }

                elem_node_idx = elem_node.next;
            }
        }
    }

    /// Collects all element IDs stored in the tree by visiting all cells.
    #[allow(dead_code)]
    pub(crate) fn collect_ids(&self) -> HashSet<ElementId> {
        let aabb: AABB = self.root_rect.into();
        self.intersect_aabb(&aabb)
    }
}

#[cfg(test)]
pub(crate) fn build_test_tree() -> QuadTree {
    let quad_rect = QuadRect::new(-20, -20, 40, 40);
    let mut tree = QuadTree::new(quad_rect, 1, 1, 1);
    // top-left
    tree.insert(QuadTreeElement::new(1000, AABB::new(-15, -15, -5, -5)))
        .expect("insert should work");
    tree.insert(QuadTreeElement::new(1001, AABB::new(-20, -20, -18, -18)))
        .expect("insert should work");
    // top-right
    tree.insert(QuadTreeElement::new(2000, AABB::new(5, -15, 15, -5)))
        .expect("insert should work");
    // bottom-left
    tree.insert(QuadTreeElement::new(3000, AABB::new(-15, 5, -5, 15)))
        .expect("insert should work");
    // bottom-right
    tree.insert(QuadTreeElement::new(4000, AABB::new(5, 5, 15, 15)))
        .expect("insert should work");
    // center
    tree.insert(QuadTreeElement::new(5000, AABB::new(-5, -5, 5, 5)))
        .expect("insert should work");

    // The depth of 1 limits the tree to four quadrants.
    // Each of the first five elements creates a single reference
    // in each of the quadrants. The "center" element covers
    // all four quadrants, and therefore adds another four references.
    assert_eq!(tree.count_element_references(), 9);

    // Ensure we have the exact elements inserted.
    let inserted_ids = tree.collect_ids();
    assert_eq!(inserted_ids.len(), 6);
    assert!(inserted_ids.contains(&1000));
    assert!(inserted_ids.contains(&1001));
    assert!(inserted_ids.contains(&2000));
    assert!(inserted_ids.contains(&3000));
    assert!(inserted_ids.contains(&4000));
    assert!(inserted_ids.contains(&5000));

    tree
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn cleanup_works() {
        let quad_rect = QuadRect::new(-20, -20, 40, 40);
        let mut tree = QuadTree::new(quad_rect, 1, 1, 1);
        // top-left
        tree.insert(QuadTreeElement::new(1000, AABB::new(-15, -15, -5, -5)))
            .expect("insert should work");
        tree.insert(QuadTreeElement::new(1001, AABB::new(-20, -20, -18, -18)))
            .expect("insert should work");
        // top-right
        tree.insert(QuadTreeElement::new(2000, AABB::new(5, -15, 15, -5)))
            .expect("insert should work");
        // bottom-left
        tree.insert(QuadTreeElement::new(3000, AABB::new(-15, 5, -5, 15)))
            .expect("insert should work");
        // bottom-right
        tree.insert(QuadTreeElement::new(4000, AABB::new(5, 5, 15, 15)))
            .expect("insert should work");
        // center
        tree.insert(QuadTreeElement::new(5000, AABB::new(-5, -5, 5, 5)))
            .expect("insert should work");

        // Similar to index test.
        assert_eq!(tree.collect_ids().len(), 6);
        assert_eq!(tree.count_element_references(), 9);

        // Erase the all elements.
        assert!(tree.remove(&QuadTreeElement::new(1000, AABB::new(-15, -15, -5, -5))));
        assert!(tree.remove(&QuadTreeElement::new(1001, AABB::new(-20, -20, -18, -18))));
        assert!(tree.remove(&QuadTreeElement::new(2000, AABB::new(5, -15, 15, -5))));
        assert!(tree.remove(&QuadTreeElement::new(3000, AABB::new(-15, 5, -5, 15))));
        assert!(tree.remove(&QuadTreeElement::new(4000, AABB::new(5, 5, 15, 15))));
        assert!(tree.remove(&QuadTreeElement::new(5000, AABB::new(-5, -5, 5, 5))));
        assert_eq!(tree.collect_ids().len(), 0);
        assert_eq!(tree.count_element_references(), 0);

        // Since cleanup wasn't called yet, the root is still considered a branch
        // with four child nodes.
        assert!(tree.nodes[0].is_branch());
        assert_eq!(tree.nodes[0].first_child_or_element, 1);

        // Cleanup does something now.
        assert!(tree.cleanup());

        // Since all four child nodes of the root were empty,
        // cleanup has removed them. The root node is now a leaf
        // with zero elements.
        assert!(tree.nodes[0].is_leaf());
        assert_eq!(tree.nodes[0].element_count, 0);
    }
}