From 2a1ccd5e3c66b01084db4612ea5f43b737e64e6d Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Mon, 6 Jan 2025 11:28:55 -0500 Subject: [PATCH 1/2] Return opaque iterator for nearest neighbor searches --- src/rtree/trait.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rtree/trait.rs b/src/rtree/trait.rs index d621c69..aeaa3d2 100644 --- a/src/rtree/trait.rs +++ b/src/rtree/trait.rs @@ -151,7 +151,7 @@ pub trait RTreeIndex: Sized { y: N, max_results: Option, max_distance: Option, - ) -> Vec { + ) -> impl Iterator { let boxes = self.boxes(); let indices = self.indices(); let max_distance = max_distance.unwrap_or(N::max_value()); @@ -212,7 +212,7 @@ pub trait RTreeIndex: Sized { } } - results + results.into_iter() } /// Search items in order of distance from the given coordinate. @@ -221,7 +221,7 @@ pub trait RTreeIndex: Sized { coord: &impl CoordTrait, max_results: Option, max_distance: Option, - ) -> Vec { + ) -> impl Iterator { self.neighbors(coord.x(), coord.y(), max_results, max_distance) } From 6732689edd679c67d866620e6a47cee65d4cdcc0 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Mon, 6 Jan 2025 11:58:14 -0500 Subject: [PATCH 2/2] wip: try to convert to iterator --- src/rtree/trait.rs | 67 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 7 deletions(-) diff --git a/src/rtree/trait.rs b/src/rtree/trait.rs index aeaa3d2..d82d354 100644 --- a/src/rtree/trait.rs +++ b/src/rtree/trait.rs @@ -1,5 +1,6 @@ use std::cmp::Reverse; use std::collections::BinaryHeap; +use std::marker::PhantomData; use geo_traits::{CoordTrait, RectTrait}; @@ -179,13 +180,13 @@ pub trait RTreeIndex: Sized { if node_index >= self.num_items() as usize * 4 { // node (use even id) - queue.push(Reverse(NeighborNode { + queue.push(Reverse(Neighbor { id: index << 1, dist, })); } else { // leaf item (use odd id) - queue.push(Reverse(NeighborNode { + queue.push(Reverse(Neighbor { id: (index << 1) + 1, dist, })); @@ -244,21 +245,28 @@ pub trait RTreeIndex: Sized { /// A wrapper around a node and its distance for use in the priority queue. #[derive(Debug, Clone, Copy, PartialEq)] -struct NeighborNode { +pub struct Neighbor { id: usize, + /// Squared distance dist: N, } -impl Eq for NeighborNode {} +impl Neighbor { + pub fn insertion_index(&self) -> u32 { + (self.id >> 1).try_into().unwrap() + } +} + +impl Eq for Neighbor {} -impl Ord for NeighborNode { +impl Ord for Neighbor { fn cmp(&self, other: &Self) -> std::cmp::Ordering { // We don't allow NaN. This should only panic on NaN self.dist.partial_cmp(&other.dist).unwrap() } } -impl PartialOrd for NeighborNode { +impl PartialOrd for Neighbor { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } @@ -293,7 +301,6 @@ impl RTreeIndex for RTreeRef<'_, N> { } /// 1D distance from a value to a range. -#[allow(dead_code)] #[inline] fn axis_dist(k: N, min: N, max: N) -> N { if k < min { @@ -305,6 +312,52 @@ fn axis_dist(k: N, min: N, max: N) -> N { } } +struct Neighbors<'a, N: IndexableNum> { + boxes: &'a [N], + indices: Indices<'a>, + outer_node_index: Option, + queue: BinaryHeap>>, +} + +impl<'a, N: IndexableNum> Neighbors<'a, N> { + fn new(boxes: &'a [N], indices: Indices<'a>) -> Self { + let outer_node_index = Some(boxes.len() - 4); + let queue = BinaryHeap::new(); + Self { + boxes, + indices, + outer_node_index, + queue, + } + } +} + +impl Iterator for Neighbors<'_, N> { + type Item = Neighbor; + + fn next(&mut self) -> Option { + // The queue is not empty and the next item in the queue is a leaf node + if !self.queue.is_empty() && self.queue.peek().is_some_and(|val| (val.0.id & 1) != 0) { + return Some(self.queue.pop().unwrap().0); + }; + + if let Some(item) = self.queue.pop() { + self.outer_node_index = Some(item.0.id >> 1); + } else { + return None; + } + + // Next: check if outer_node_index is not None + // Then: Add child nodes to the queue + + if let Some(node_index) = self.outer_node_index { + } else { + None + } + todo!() + } +} + #[cfg(test)] mod test { // Replication of tests from flatbush js