1use std::collections::HashMap;
10
11use crate::backends::SpatialBackend;
12use crate::types::{BBox, BackendKind, CoordType, EntryId, Point};
13
14const LEAF_CAPACITY: usize = 8;
15const MAX_DEPTH: usize = 20;
16
17struct QuadNode<C, const D: usize> {
18 bounds: BBox<C, D>,
19 loose_bounds: BBox<C, D>,
20 entries: Vec<(Point<C, D>, EntryId)>,
21 children: Option<Vec<QuadNode<C, D>>>,
22 depth: usize,
23}
24
25impl<C: CoordType, const D: usize> QuadNode<C, D> {
26 fn new_leaf(bounds: BBox<C, D>, loose_bounds: BBox<C, D>, depth: usize) -> Self {
27 Self {
28 bounds,
29 loose_bounds,
30 entries: Vec::new(),
31 children: None,
32 depth,
33 }
34 }
35
36 fn child_index(&self, point: &Point<C, D>) -> usize {
40 let mut idx = 0usize;
41 for d in 0..D {
42 let lo: f64 = self.bounds.min.coords()[d].into();
43 let hi: f64 = self.bounds.max.coords()[d].into();
44 let mid: C = C::from(((lo + hi) * 0.5) as f32);
45 if point.coords()[d] >= mid {
46 idx |= 1 << d;
47 }
48 }
49 idx
50 }
51
52 fn make_children(&self) -> Vec<QuadNode<C, D>> {
53 let num_children = 1usize << D;
54 let mut children = Vec::with_capacity(num_children);
55 for ci in 0..num_children {
56 let mut child_min = [C::zero(); D];
57 let mut child_max = [C::zero(); D];
58 for d in 0..D {
59 let lo: f64 = self.bounds.min.coords()[d].into();
60 let hi: f64 = self.bounds.max.coords()[d].into();
61 let mid = (lo + hi) * 0.5;
62 if (ci >> d) & 1 == 0 {
63 child_min[d] = C::from(lo as f32);
64 child_max[d] = C::from(mid as f32);
65 } else {
66 child_min[d] = C::from(mid as f32);
67 child_max[d] = C::from(hi as f32);
68 }
69 }
70 let child_bounds = BBox::new(Point::new(child_min), Point::new(child_max));
71 let mut loose_min = [C::zero(); D];
72 let mut loose_max = [C::zero(); D];
73 for d in 0..D {
74 let lo: f64 = child_bounds.min.coords()[d].into();
75 let hi: f64 = child_bounds.max.coords()[d].into();
76 let half = (hi - lo) * 0.5;
77 loose_min[d] = C::from((lo - half) as f32);
78 loose_max[d] = C::from((hi + half) as f32);
79 }
80 let loose_bounds = BBox::new(Point::new(loose_min), Point::new(loose_max));
81 children.push(QuadNode::new_leaf(
82 child_bounds,
83 loose_bounds,
84 self.depth + 1,
85 ));
86 }
87 children
88 }
89
90 fn insert(&mut self, point: Point<C, D>, id: EntryId) {
91 #[allow(clippy::unnecessary_unwrap)]
92 if self.children.is_some() {
93 let ci = self.child_index(&point);
94 self.children.as_mut().unwrap()[ci].insert(point, id);
95 return;
96 }
97 self.entries.push((point, id));
98 if self.entries.len() > LEAF_CAPACITY && self.depth < MAX_DEPTH {
99 self.split();
100 }
101 }
102
103 fn split(&mut self) {
104 let mut children = self.make_children();
105 let entries: Vec<(Point<C, D>, EntryId)> = self.entries.drain(..).collect();
106 for (pt, id) in entries {
107 let ci = self.child_index(&pt);
108 children[ci].entries.push((pt, id));
109 }
110 self.children = Some(children);
111 }
112
113 fn remove(&mut self, id: EntryId) -> bool {
114 if let Some(ref mut children) = self.children {
115 for child in children.iter_mut() {
116 if child.remove(id) {
117 return true;
118 }
119 }
120 return false;
121 }
122 if let Some(pos) = self.entries.iter().position(|(_, eid)| *eid == id) {
123 self.entries.swap_remove(pos);
124 return true;
125 }
126 false
127 }
128
129 fn range_query(&self, bbox: &BBox<C, D>, out: &mut Vec<EntryId>) {
130 if !self.loose_bounds.intersects(bbox) {
131 return;
132 }
133 if let Some(ref children) = self.children {
134 for child in children {
135 child.range_query(bbox, out);
136 }
137 return;
138 }
139 for (pt, id) in &self.entries {
140 if bbox.contains_point(pt) {
141 out.push(*id);
142 }
143 }
144 }
145
146 fn collect_all(&self, out: &mut Vec<(Point<C, D>, EntryId)>) {
147 if let Some(ref children) = self.children {
148 for child in children {
149 child.collect_all(out);
150 }
151 return;
152 }
153 out.extend_from_slice(&self.entries);
154 }
155
156 fn node_count(&self) -> usize {
157 match &self.children {
158 None => 1,
159 Some(children) => 1 + children.iter().map(|c| c.node_count()).sum::<usize>(),
160 }
161 }
162
163 fn max_depth(&self) -> usize {
164 match &self.children {
165 None => self.depth,
166 Some(children) => children
167 .iter()
168 .map(|c| c.max_depth())
169 .max()
170 .unwrap_or(self.depth),
171 }
172 }
173}
174
175pub struct Quadtree<T, C, const D: usize> {
182 root: QuadNode<C, D>,
183 id_to_payload: HashMap<u64, T>,
184 id_to_point: HashMap<u64, Point<C, D>>,
185 len: usize,
186 next_id: u64,
187}
188
189impl<T, C: CoordType, const D: usize> Quadtree<T, C, D> {
190 pub fn new() -> Self {
192 Self::with_bounds(
193 Point::new([C::zero(); D]),
194 Point::new([C::from(1.0_f32); D]),
195 )
196 }
197
198 pub fn with_bounds(min: Point<C, D>, max: Point<C, D>) -> Self {
200 let bounds = BBox::new(min, max);
201 let mut loose_min = [C::zero(); D];
202 let mut loose_max = [C::zero(); D];
203 for d in 0..D {
204 let lo: f64 = min.coords()[d].into();
205 let hi: f64 = max.coords()[d].into();
206 let half = (hi - lo) * 0.5;
207 loose_min[d] = C::from((lo - half) as f32);
208 loose_max[d] = C::from((hi + half) as f32);
209 }
210 let loose_bounds = BBox::new(Point::new(loose_min), Point::new(loose_max));
211 Self {
212 root: QuadNode::new_leaf(bounds, loose_bounds, 0),
213 id_to_payload: HashMap::new(),
214 id_to_point: HashMap::new(),
215 len: 0,
216 next_id: 0,
217 }
218 }
219
220 fn alloc_id(&mut self) -> EntryId {
221 let id = EntryId(self.next_id);
222 self.next_id += 1;
223 id
224 }
225
226 fn ensure_bounds(&mut self, point: &Point<C, D>) {
227 let mut needs_expand = false;
228 for d in 0..D {
229 let v: f64 = point.coords()[d].into();
230 let lo: f64 = self.root.bounds.min.coords()[d].into();
231 let hi: f64 = self.root.bounds.max.coords()[d].into();
232 if v < lo || v > hi {
233 needs_expand = true;
234 break;
235 }
236 }
237 if !needs_expand {
238 return;
239 }
240 let mut all: Vec<(Point<C, D>, EntryId)> = Vec::with_capacity(self.len);
241 self.root.collect_all(&mut all);
242
243 let mut new_min = [C::zero(); D];
244 let mut new_max = [C::zero(); D];
245 for d in 0..D {
246 let lo: f64 = self.root.bounds.min.coords()[d].into();
247 let hi: f64 = self.root.bounds.max.coords()[d].into();
248 let v: f64 = point.coords()[d].into();
249 let span = (hi - lo).max(1.0);
250 let new_lo = lo.min(v - span * 0.1);
251 let new_hi = hi.max(v + span * 0.1);
252 new_min[d] = C::from(new_lo as f32);
253 new_max[d] = C::from(new_hi as f32);
254 }
255
256 let mut new_tree = Quadtree::with_bounds(Point::new(new_min), Point::new(new_max));
257 new_tree.next_id = self.next_id;
258 for (pt, id) in all {
259 new_tree.root.insert(pt, id);
260 new_tree.id_to_point.insert(id.0, pt);
261 }
262 new_tree.id_to_payload = std::mem::take(&mut self.id_to_payload);
263 new_tree.len = self.len;
264 *self = new_tree;
265 }
266
267 pub fn insert_entry(&mut self, point: Point<C, D>, payload: T) -> EntryId {
268 self.ensure_bounds(&point);
269 let id = self.alloc_id();
270 self.id_to_point.insert(id.0, point);
271 self.id_to_payload.insert(id.0, payload);
272 self.root.insert(point, id);
273 self.len += 1;
274 id
275 }
276
277 pub fn remove_entry(&mut self, id: EntryId) -> Option<T> {
278 self.id_to_point.remove(&id.0)?;
279 let payload = self.id_to_payload.remove(&id.0)?;
280 self.root.remove(id);
281 self.len -= 1;
282 Some(payload)
283 }
284
285 pub fn range_query_impl<'a>(&'a self, bbox: &BBox<C, D>) -> Vec<(EntryId, &'a T)> {
286 let mut ids = Vec::new();
287 self.root.range_query(bbox, &mut ids);
288 ids.into_iter()
289 .filter_map(|id| self.id_to_payload.get(&id.0).map(|p| (id, p)))
290 .collect()
291 }
292
293 pub fn knn_query_impl<'a>(
294 &'a self,
295 point: &Point<C, D>,
296 k: usize,
297 ) -> Vec<(f64, EntryId, &'a T)> {
298 if k == 0 {
299 return Vec::new();
300 }
301 let mut all: Vec<(Point<C, D>, EntryId)> = Vec::with_capacity(self.len);
302 self.root.collect_all(&mut all);
303 let mut results: Vec<(f64, EntryId, &'a T)> = all
304 .into_iter()
305 .filter_map(|(p, id)| {
306 self.id_to_payload.get(&id.0).map(|payload| {
307 let dist = point_dist_sq(&p, point).sqrt();
308 (dist, id, payload)
309 })
310 })
311 .collect();
312 results.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(std::cmp::Ordering::Equal));
313 results.truncate(k);
314 results
315 }
316
317 fn collect_all_with_payload(&self) -> Vec<(Point<C, D>, EntryId, &T)> {
318 let mut raw: Vec<(Point<C, D>, EntryId)> = Vec::with_capacity(self.len);
319 self.root.collect_all(&mut raw);
320 raw.into_iter()
321 .filter_map(|(p, id)| {
322 self.id_to_payload
323 .get(&id.0)
324 .map(|payload| (p, id, payload))
325 })
326 .collect()
327 }
328
329 pub fn node_count(&self) -> usize {
331 self.root.node_count()
332 }
333
334 pub fn max_depth(&self) -> usize {
336 self.root.max_depth()
337 }
338}
339
340fn point_dist_sq<C: CoordType, const D: usize>(a: &Point<C, D>, b: &Point<C, D>) -> f64 {
341 let mut sum = 0.0_f64;
342 for d in 0..D {
343 let da: f64 = a.coords()[d].into();
344 let db: f64 = b.coords()[d].into();
345 let diff = da - db;
346 sum += diff * diff;
347 }
348 sum
349}
350
351impl<T, C: CoordType, const D: usize> Default for Quadtree<T, C, D> {
352 fn default() -> Self {
353 Self::new()
354 }
355}
356
357impl<T: Send + Sync + 'static, C: CoordType, const D: usize> SpatialBackend<T, C, D>
358 for Quadtree<T, C, D>
359{
360 fn insert(&mut self, point: Point<C, D>, payload: T) -> EntryId {
361 self.insert_entry(point, payload)
362 }
363
364 fn remove(&mut self, id: EntryId) -> Option<T> {
365 self.remove_entry(id)
366 }
367
368 fn range_query(&self, bbox: &BBox<C, D>) -> Vec<(EntryId, &T)> {
369 self.range_query_impl(bbox)
370 }
371
372 fn knn_query(&self, point: &Point<C, D>, k: usize) -> Vec<(f64, EntryId, &T)> {
373 self.knn_query_impl(point, k)
374 }
375
376 fn spatial_join(&self, other: &dyn SpatialBackend<T, C, D>) -> Vec<(EntryId, EntryId)> {
377 let self_entries = self.collect_all_with_payload();
378 let other_entries = other.all_entries();
379 let mut pairs = Vec::new();
380 for (pa, id_a, _) in &self_entries {
381 let bbox_a = BBox::new(*pa, *pa);
382 for (pb, id_b, _) in &other_entries {
383 if bbox_a.intersects(&BBox::new(*pb, *pb)) {
384 pairs.push((*id_a, *id_b));
385 }
386 }
387 }
388 pairs
389 }
390
391 fn bulk_load(entries: Vec<(Point<C, D>, T)>) -> Self {
392 if entries.is_empty() {
393 return Self::new();
394 }
395 let mut min_c = *entries[0].0.coords();
396 let mut max_c = *entries[0].0.coords();
397 for (p, _) in &entries {
398 for d in 0..D {
399 let v = p.coords()[d];
400 if v < min_c[d] {
401 min_c[d] = v;
402 }
403 if v > max_c[d] {
404 max_c[d] = v;
405 }
406 }
407 }
408 let mut padded_min = [C::zero(); D];
409 let mut padded_max = [C::zero(); D];
410 for d in 0..D {
411 let lo: f64 = min_c[d].into();
412 let hi: f64 = max_c[d].into();
413 let margin = ((hi - lo) * 0.01).max(1.0);
414 padded_min[d] = C::from((lo - margin) as f32);
415 padded_max[d] = C::from((hi + margin) as f32);
416 }
417 let mut tree = Self::with_bounds(Point::new(padded_min), Point::new(padded_max));
418 for (point, payload) in entries {
419 tree.insert_entry(point, payload);
420 }
421 tree
422 }
423
424 fn len(&self) -> usize {
425 self.len
426 }
427
428 fn kind(&self) -> BackendKind {
429 BackendKind::Quadtree
430 }
431
432 fn all_entries(&self) -> Vec<(Point<C, D>, EntryId, &T)> {
433 self.collect_all_with_payload()
434 }
435}
436
437#[cfg(test)]
438mod tests {
439 use super::*;
440 use proptest::prelude::*;
441
442 struct Lcg(u64);
443 impl Lcg {
444 fn new(seed: u64) -> Self {
445 Self(seed)
446 }
447 fn next_f64(&mut self) -> f64 {
448 self.0 = self
449 .0
450 .wrapping_mul(6_364_136_223_846_793_005)
451 .wrapping_add(1_442_695_040_888_963_407);
452 (self.0 >> 11) as f64 / (1u64 << 53) as f64
453 }
454 }
455
456 fn rand_pts<const D: usize>(n: usize, seed: u64) -> Vec<Point<f64, D>> {
457 let mut rng = Lcg::new(seed);
458 (0..n)
459 .map(|_| {
460 let coords: [f64; D] = std::array::from_fn(|_| rng.next_f64() * 1000.0);
461 Point::new(coords)
462 })
463 .collect()
464 }
465
466 fn brute_range<C: CoordType, const D: usize>(
467 pts: &[(Point<C, D>, EntryId)],
468 bbox: &BBox<C, D>,
469 ) -> Vec<EntryId> {
470 let mut ids: Vec<EntryId> = pts
471 .iter()
472 .filter(|(p, _)| bbox.contains_point(p))
473 .map(|(_, id)| *id)
474 .collect();
475 ids.sort_by_key(|id| id.0);
476 ids
477 }
478
479 #[test]
480 fn children_count_d2() {
481 let pts = rand_pts::<2>(200, 1);
482 let mut tree = Quadtree::<usize, f64, 2>::bulk_load(
483 pts.into_iter().enumerate().map(|(i, p)| (p, i)).collect(),
484 );
485 for i in 200..300usize {
486 tree.insert(rand_pts::<2>(1, i as u64 + 9999)[0], i);
487 }
488 assert!(tree.root.children.is_some());
489 assert_eq!(tree.root.children.as_ref().unwrap().len(), 1 << 2);
490 }
491
492 #[test]
493 fn children_count_d3() {
494 let pts = rand_pts::<3>(200, 2);
495 let mut tree = Quadtree::<usize, f64, 3>::bulk_load(
496 pts.into_iter().enumerate().map(|(i, p)| (p, i)).collect(),
497 );
498 for i in 200..300usize {
499 tree.insert(rand_pts::<3>(1, i as u64 + 8888)[0], i);
500 }
501 assert!(tree.root.children.is_some());
502 assert_eq!(tree.root.children.as_ref().unwrap().len(), 1 << 3);
503 }
504
505 #[test]
506 fn children_count_d4() {
507 let pts = rand_pts::<4>(200, 3);
508 let mut tree = Quadtree::<usize, f64, 4>::bulk_load(
509 pts.into_iter().enumerate().map(|(i, p)| (p, i)).collect(),
510 );
511 for i in 200..300usize {
512 tree.insert(rand_pts::<4>(1, i as u64 + 7777)[0], i);
513 }
514 assert!(tree.root.children.is_some());
515 assert_eq!(tree.root.children.as_ref().unwrap().len(), 1 << 4);
516 }
517
518 #[test]
519 fn each_point_assigned_to_exactly_one_child_d2() {
520 let pts = rand_pts::<2>(300, 42);
521 let tree = Quadtree::<usize, f64, 2>::bulk_load(
522 pts.iter()
523 .cloned()
524 .enumerate()
525 .map(|(i, p)| (p, i))
526 .collect(),
527 );
528 if let Some(ref children) = tree.root.children {
529 let mut all_ids: Vec<EntryId> = Vec::new();
530 for child in children {
531 let mut child_entries: Vec<(Point<f64, 2>, EntryId)> = Vec::new();
532 child.collect_all(&mut child_entries);
533 all_ids.extend(child_entries.iter().map(|(_, id)| *id));
534 }
535 all_ids.sort_by_key(|id| id.0);
536 let before = all_ids.len();
537 all_ids.dedup();
538 assert_eq!(before, all_ids.len());
539 }
540 }
541
542 #[test]
543 fn range_query_basic() {
544 let mut tree = Quadtree::<u32, f64, 2>::new();
545 let id1 = tree.insert(Point::new([0.5, 0.5]), 1u32);
546 let id2 = tree.insert(Point::new([1.5, 1.5]), 2u32);
547 let _id3 = tree.insert(Point::new([5.0, 5.0]), 3u32);
548 let bbox = BBox::new(Point::new([0.0, 0.0]), Point::new([2.0, 2.0]));
549 let mut got: Vec<EntryId> = tree
550 .range_query(&bbox)
551 .into_iter()
552 .map(|(id, _)| id)
553 .collect();
554 got.sort_by_key(|id| id.0);
555 assert_eq!(got, vec![id1, id2]);
556 }
557
558 #[test]
559 fn remove_works() {
560 let mut tree = Quadtree::<u32, f64, 2>::new();
561 let id1 = tree.insert(Point::new([1.0, 1.0]), 10u32);
562 let id2 = tree.insert(Point::new([2.0, 2.0]), 20u32);
563 assert_eq!(tree.len(), 2);
564 assert_eq!(tree.remove(id1), Some(10u32));
565 assert_eq!(tree.len(), 1);
566 let bbox = BBox::new(Point::new([0.0, 0.0]), Point::new([3.0, 3.0]));
567 let ids: Vec<EntryId> = tree
568 .range_query(&bbox)
569 .into_iter()
570 .map(|(id, _)| id)
571 .collect();
572 assert!(!ids.contains(&id1));
573 assert!(ids.contains(&id2));
574 }
575
576 #[test]
577 fn kind_is_quadtree() {
578 assert_eq!(Quadtree::<u32, f64, 2>::new().kind(), BackendKind::Quadtree);
579 }
580
581 #[test]
582 fn range_query_vs_brute_force_2d() {
583 let pts = rand_pts::<2>(1000, 99);
584 let mut tree = Quadtree::<usize, f64, 2>::new();
585 let mut pt_ids: Vec<(Point<f64, 2>, EntryId)> = Vec::new();
586 for (i, &p) in pts.iter().enumerate() {
587 let id = tree.insert(p, i);
588 pt_ids.push((p, id));
589 }
590 let bbox = BBox::new(Point::new([0.0, 0.0]), Point::new([500.0, 500.0]));
591 let mut got: Vec<EntryId> = tree
592 .range_query(&bbox)
593 .into_iter()
594 .map(|(id, _)| id)
595 .collect();
596 got.sort_by_key(|id| id.0);
597 let expected = brute_range(&pt_ids, &bbox);
598 assert_eq!(got, expected);
599 }
600
601 fn pt2d() -> impl Strategy<Value = Point<f64, 2>> {
602 (0.0_f64..1000.0, 0.0_f64..1000.0).prop_map(|(x, y)| Point::new([x, y]))
603 }
604
605 fn bbox2d() -> impl Strategy<Value = BBox<f64, 2>> {
606 (
607 0.0_f64..900.0,
608 0.0_f64..900.0,
609 10.0_f64..200.0,
610 10.0_f64..200.0,
611 )
612 .prop_map(|(x, y, w, h)| BBox::new(Point::new([x, y]), Point::new([x + w, y + h])))
613 }
614
615 proptest! {
618 #![proptest_config(proptest::test_runner::Config {
619 cases: 100,
620 ..Default::default()
621 })]
622
623 #[test]
624 fn prop_quadtree_children_count_d2(
625 pts in prop::collection::vec(pt2d(), (LEAF_CAPACITY + 1)..50),
626 ) {
627 let mut tree = Quadtree::<usize, f64, 2>::new();
628 for (i, p) in pts.iter().enumerate() {
629 tree.insert(*p, i);
630 }
631 if let Some(ref children) = tree.root.children {
632 prop_assert_eq!(children.len(), 1 << 2usize);
633 for child in children {
634 if let Some(ref gc) = child.children {
635 prop_assert_eq!(gc.len(), 1 << 2usize);
636 }
637 }
638 }
639 let mut raw: Vec<(Point<f64, 2>, EntryId)> = Vec::new();
640 tree.root.collect_all(&mut raw);
641 let mut all_ids: Vec<EntryId> = raw.iter().map(|(_, id)| *id).collect();
642 all_ids.sort_by_key(|id| id.0);
643 let before = all_ids.len();
644 all_ids.dedup();
645 prop_assert_eq!(before, all_ids.len());
646 prop_assert_eq!(all_ids.len(), pts.len());
647 }
648 }
649
650 proptest! {
652 #![proptest_config(proptest::test_runner::Config {
653 cases: 100,
654 ..Default::default()
655 })]
656
657 #[test]
658 fn prop_insert_remove_round_trip_quadtree(
659 pts in prop::collection::vec(pt2d(), 1..50),
660 remove_indices in prop::collection::vec(0usize..50, 0..25),
661 ) {
662 let mut tree = Quadtree::<usize, f64, 2>::new();
663 let mut inserted: Vec<(Point<f64, 2>, EntryId)> = Vec::new();
664 for (i, &p) in pts.iter().enumerate() {
665 let id = tree.insert(p, i);
666 inserted.push((p, id));
667 }
668 let mut removed_ids: Vec<EntryId> = Vec::new();
669 for &ri in &remove_indices {
670 let idx = ri % inserted.len();
671 let (_, id) = inserted[idx];
672 if !removed_ids.contains(&id) {
673 let result = tree.remove(id);
674 prop_assert!(result.is_some(), "remove returned None for inserted id");
675 removed_ids.push(id);
676 }
677 }
678 let full_bbox = BBox::new(Point::new([-1.0e9, -1.0e9]), Point::new([1.0e9, 1.0e9]));
679 let remaining_ids: Vec<EntryId> = tree.range_query(&full_bbox)
680 .into_iter()
681 .map(|(id, _)| id)
682 .collect();
683 for &removed_id in &removed_ids {
684 prop_assert!(
685 !remaining_ids.contains(&removed_id),
686 "removed entry {:?} still appears in range query",
687 removed_id
688 );
689 }
690 let expected_len = inserted.len() - removed_ids.len();
691 prop_assert_eq!(tree.len(), expected_len);
692 }
693 }
694
695 proptest! {
697 #![proptest_config(proptest::test_runner::Config {
698 cases: 100,
699 ..Default::default()
700 })]
701
702 #[test]
703 fn prop_range_query_oracle_quadtree(
704 pts in prop::collection::vec(pt2d(), 1..100),
705 bbox in bbox2d(),
706 ) {
707 let mut tree = Quadtree::<usize, f64, 2>::new();
708 let mut pt_ids: Vec<(Point<f64, 2>, EntryId)> = Vec::new();
709 for (i, p) in pts.iter().enumerate() {
710 let id = tree.insert(*p, i);
711 pt_ids.push((*p, id));
712 }
713 let mut got: Vec<EntryId> =
714 tree.range_query(&bbox).into_iter().map(|(id, _)| id).collect();
715 got.sort_by_key(|id| id.0);
716 let expected = brute_range(&pt_ids, &bbox);
717 prop_assert_eq!(got, expected);
718 }
719 }
720}