Skip to content

Commit 327c549

Browse files
authored
KDTree traversal (#96)
* KDTree traversal * KDTree traversal
1 parent c7bc4f9 commit 327c549

File tree

6 files changed

+335
-48
lines changed

6 files changed

+335
-48
lines changed

src/kdtree/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,12 @@ mod builder;
5353
pub(crate) mod constants;
5454
mod index;
5555
mod r#trait;
56+
mod traversal;
5657

5758
pub use builder::{KDTreeBuilder, DEFAULT_KDTREE_NODE_SIZE};
5859
pub use index::{KDTree, KDTreeMetadata, KDTreeRef};
5960
pub use r#trait::KDTreeIndex;
61+
pub use traversal::Node;
6062

6163
#[cfg(test)]
6264
mod test;

src/kdtree/trait.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ use geo_traits::{CoordTrait, RectTrait};
22
use tinyvec::TinyVec;
33

44
use crate::indices::Indices;
5-
use crate::kdtree::{KDTree, KDTreeMetadata, KDTreeRef};
5+
use crate::kdtree::{KDTree, KDTreeMetadata, KDTreeRef, Node};
66
use crate::r#type::IndexableNum;
77

88
/// A trait for searching and accessing data out of a KDTree.
9-
pub trait KDTreeIndex<N: IndexableNum> {
9+
pub trait KDTreeIndex<N: IndexableNum>: Sized {
1010
/// The underlying raw coordinate buffer of this tree
1111
fn coords(&self) -> &[N];
1212

@@ -78,13 +78,15 @@ pub trait KDTreeIndex<N: IndexableNum> {
7878
// queue search in halves that intersect the query
7979
let lte = if axis == 0 { min_x <= x } else { min_y <= y };
8080
if lte {
81+
// Note: these are pushed in backwards order to what gets popped
8182
stack.push(left);
8283
stack.push(m - 1);
8384
stack.push(1 - axis);
8485
}
8586

8687
let gte = if axis == 0 { max_x >= x } else { max_y >= y };
8788
if gte {
89+
// Note: these are pushed in backwards order to what gets popped
8890
stack.push(m + 1);
8991
stack.push(right);
9092
stack.push(1 - axis);
@@ -180,6 +182,11 @@ pub trait KDTreeIndex<N: IndexableNum> {
180182
fn within_coord(&self, coord: &impl CoordTrait<T = N>, r: N) -> Vec<u32> {
181183
self.within(coord.x(), coord.y(), r)
182184
}
185+
186+
/// Access the root node of the KDTree for manual traversal.
187+
fn root(&self) -> Node<'_, N, Self> {
188+
Node::from_root(self)
189+
}
183190
}
184191

185192
impl<N: IndexableNum> KDTreeIndex<N> for KDTree<N> {

src/kdtree/traversal.rs

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
//! Utilities to traverse the KDTree structure.
2+
3+
use geo_traits::RectTrait;
4+
5+
use crate::kdtree::KDTreeIndex;
6+
use crate::r#type::{Coord, IndexableNum};
7+
use std::marker::PhantomData;
8+
9+
/// An internal node in the KDTree.
10+
#[derive(Debug, Clone)]
11+
pub struct Node<'a, N: IndexableNum, T: KDTreeIndex<N>> {
12+
/// The tree that this node is a reference onto
13+
tree: &'a T,
14+
15+
/// The axis that the children of this node are split over.
16+
/// 0 for x axis, 1 for y axis
17+
/// TODO: switch to bool
18+
axis: usize,
19+
20+
/// The index of the right child.
21+
right_child: usize,
22+
23+
/// The index of the left child.
24+
left_child: usize,
25+
26+
/// The min_x of this node.
27+
min_x: N,
28+
/// The min_y of this node.
29+
min_y: N,
30+
/// The max_x of this node.
31+
max_x: N,
32+
/// The max_y of this node.
33+
max_y: N,
34+
35+
phantom: PhantomData<N>,
36+
}
37+
38+
impl<'a, N: IndexableNum, T: KDTreeIndex<N>> Node<'a, N, T> {
39+
pub(crate) fn from_root(tree: &'a T) -> Self {
40+
Self {
41+
tree,
42+
axis: 0,
43+
right_child: tree.indices().len() - 1,
44+
left_child: 0,
45+
min_x: N::max_value(),
46+
min_y: N::max_value(),
47+
max_x: N::min_value(),
48+
max_y: N::min_value(),
49+
phantom: PhantomData,
50+
}
51+
}
52+
53+
// TODO: perhaps this should be state stored on the node, so we don't have to recompute it
54+
// But it's only valid for nodes that have children
55+
/// Note: this is the index into the coords array, not the insertion index.
56+
#[inline]
57+
pub(crate) fn middle_index(&self) -> usize {
58+
(self.left_child + self.right_child) >> 1
59+
}
60+
61+
// TODO: perhaps this should be state stored on the node, so we don't have to recompute it
62+
// But it's only valid for nodes that have children
63+
#[inline]
64+
pub(crate) fn middle_xy(&self, m: usize) -> (N, N) {
65+
let x = self.tree.coords()[2 * m];
66+
let y = self.tree.coords()[2 * m + 1];
67+
(x, y)
68+
}
69+
70+
/// The child node representing the "left" half.
71+
///
72+
/// Returns `None` if [`Self::is_parent`] is `false`.
73+
pub fn left_child(&self) -> Option<Node<'_, N, T>> {
74+
if self.is_parent() {
75+
Some(self.left_child_unchecked())
76+
} else {
77+
None
78+
}
79+
}
80+
81+
/// The child node representing the "left" half.
82+
///
83+
/// Note that this **does not include** the middle index of the current node.
84+
pub fn left_child_unchecked(&self) -> Node<'_, N, T> {
85+
debug_assert!(self.is_parent());
86+
87+
let m = self.middle_index();
88+
let (x, y) = self.middle_xy(m);
89+
90+
let mut max_x = self.max_x;
91+
let mut max_y = self.max_y;
92+
if self.axis == 0 {
93+
max_x = x;
94+
} else {
95+
max_y = y;
96+
};
97+
98+
Self {
99+
tree: self.tree,
100+
axis: 1 - self.axis,
101+
right_child: m - 1,
102+
left_child: self.left_child,
103+
min_x: self.min_x,
104+
min_y: self.min_y,
105+
max_x,
106+
max_y,
107+
phantom: self.phantom,
108+
}
109+
}
110+
111+
/// The child node representing the "right" half.
112+
///
113+
/// Returns `None` if [`Self::is_parent`] is `false`.
114+
pub fn right_child(&self) -> Option<Node<'_, N, T>> {
115+
if self.is_parent() {
116+
Some(self.right_child_unchecked())
117+
} else {
118+
None
119+
}
120+
}
121+
122+
/// The child node representing the "right" half.
123+
///
124+
/// Note that this **does not include** the middle index of the current node.
125+
pub fn right_child_unchecked(&self) -> Node<'_, N, T> {
126+
debug_assert!(self.is_parent());
127+
128+
let m = self.middle_index();
129+
let (x, y) = self.middle_xy(m);
130+
131+
let mut min_x = self.min_x;
132+
let mut min_y = self.min_y;
133+
if self.axis == 0 {
134+
min_x = x;
135+
} else {
136+
min_y = y;
137+
};
138+
139+
Self {
140+
tree: self.tree,
141+
axis: 1 - self.axis,
142+
right_child: self.right_child,
143+
left_child: m + 1,
144+
min_x,
145+
min_y,
146+
max_x: self.max_x,
147+
max_y: self.max_y,
148+
phantom: self.phantom,
149+
}
150+
}
151+
152+
/// Returns `true` if this is a leaf node without children.
153+
#[inline]
154+
pub fn is_leaf(&self) -> bool {
155+
self.right_child - self.left_child <= self.tree.node_size() as usize
156+
}
157+
158+
/// Returns `true` if this is an intermediate node with children.
159+
#[inline]
160+
pub fn is_parent(&self) -> bool {
161+
!self.is_leaf()
162+
}
163+
164+
/// The original insertion index of the "middle child" of this node. This is only valid when
165+
/// this is a parent node, which you can check with `Self::is_parent`.
166+
///
167+
/// Returns `None` if [`Self::is_parent`] is `false`.
168+
#[inline]
169+
pub fn middle_insertion_index(&self) -> Option<u32> {
170+
if self.is_parent() {
171+
Some(self.middle_insertion_index_unchecked())
172+
} else {
173+
None
174+
}
175+
}
176+
177+
/// The original insertion index of the "middle child" of this node. This is only valid when
178+
/// this is a parent node, which you can check with `Self::is_parent`.
179+
#[inline]
180+
pub fn middle_insertion_index_unchecked(&self) -> u32 {
181+
debug_assert!(self.is_parent());
182+
183+
let m = self.middle_index();
184+
let indices = self.tree.indices();
185+
indices.get(m) as u32
186+
}
187+
188+
/// The original insertion indices. This is only valid when this is a leaf node, which you can
189+
/// check with `Self::is_leaf`.
190+
///
191+
/// Returns `None` if [`Self::is_leaf`] is `false`.
192+
#[inline]
193+
pub fn leaf_insertion_indices(&self) -> Option<Vec<u32>> {
194+
if self.is_leaf() {
195+
Some(self.leaf_insertion_indices_unchecked())
196+
} else {
197+
None
198+
}
199+
}
200+
201+
/// The original insertion indices. This is only valid when this is a leaf node, which you can
202+
/// check with `Self::is_leaf`.
203+
#[inline]
204+
pub fn leaf_insertion_indices_unchecked(&self) -> Vec<u32> {
205+
debug_assert!(self.is_leaf());
206+
207+
let mut result = Vec::with_capacity(self.tree.node_size() as _);
208+
209+
let indices = self.tree.indices();
210+
for i in self.left_child..self.right_child + 1 {
211+
result.push(indices.get(i) as u32);
212+
}
213+
214+
result
215+
}
216+
}
217+
218+
impl<N: IndexableNum, T: KDTreeIndex<N>> RectTrait for Node<'_, N, T> {
219+
type T = N;
220+
type CoordType<'a>
221+
= Coord<N>
222+
where
223+
Self: 'a;
224+
225+
fn dim(&self) -> geo_traits::Dimensions {
226+
geo_traits::Dimensions::Xy
227+
}
228+
229+
fn min(&self) -> Self::CoordType<'_> {
230+
Coord {
231+
x: self.min_x,
232+
y: self.min_y,
233+
}
234+
}
235+
236+
fn max(&self) -> Self::CoordType<'_> {
237+
Coord {
238+
x: self.max_x,
239+
y: self.max_y,
240+
}
241+
}
242+
}

src/rtree/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,10 @@ mod constants;
5959
mod index;
6060
pub mod sort;
6161
mod r#trait;
62-
pub mod traversal;
62+
mod traversal;
6363
pub mod util;
6464

6565
pub use builder::{RTreeBuilder, DEFAULT_RTREE_NODE_SIZE};
6666
pub use index::{RTree, RTreeMetadata, RTreeRef};
6767
pub use r#trait::RTreeIndex;
68+
pub use traversal::Node;

0 commit comments

Comments
 (0)