Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Add geo-traits integration #71

Merged
merged 1 commit into from
Dec 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ categories = ["data-structures", "algorithms", "science::geo"]
[dependencies]
bytemuck = "1"
float_next_after = "1"
geo-traits = "0.2"
num-traits = "0.2"
rayon = { version = "1.8.0", optional = true }
thiserror = "1"
Expand Down
31 changes: 30 additions & 1 deletion src/kdtree/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ use std::cmp;
use std::marker::PhantomData;

use bytemuck::cast_slice_mut;
use geo_traits::{CoordTrait, PointTrait};

use crate::error::Result;
use crate::indices::MutableIndices;
use crate::kdtree::constants::{KDBUSH_HEADER_SIZE, KDBUSH_MAGIC, KDBUSH_VERSION};
use crate::kdtree::OwnedKDTree;
use crate::r#type::IndexableNum;
use crate::GeoIndexError;

const DEFAULT_NODE_SIZE: u16 = 64;

Expand Down Expand Up @@ -68,7 +71,10 @@ impl<N: IndexableNum> KDTreeBuilder<N> {
}
}

/// Add a point to the index.
/// Add a point to the KDTree.
///
/// This returns a positional index that provides a lookup back into the original data.
#[inline]
pub fn add(&mut self, x: N, y: N) -> usize {
let index = self.pos >> 1;
let (coords, mut ids) = split_data_borrow(
Expand All @@ -88,6 +94,29 @@ impl<N: IndexableNum> KDTreeBuilder<N> {
index
}

/// Add a coord to the KDTree.
///
/// This returns a positional index that provides a lookup back into the original data.
#[inline]
pub fn add_coord(&mut self, coord: &impl CoordTrait<T = N>) -> usize {
self.add(coord.x(), coord.y())
}

/// Add a point to the KDTree.
///
/// This returns a positional index that provides a lookup back into the original data.
///
/// ## Errors
///
/// - If the point is empty.
#[inline]
pub fn add_point(&mut self, point: &impl PointTrait<T = N>) -> Result<usize> {
let coord = point.coord().ok_or(GeoIndexError::General(
"Unable to add empty point to KDTree".to_string(),
))?;
Ok(self.add_coord(&coord))
}

/// Consume this builder, perfoming the k-d sort and generating a KDTree ready for queries.
pub fn finish(mut self) -> OwnedKDTree<N> {
assert_eq!(
Expand Down
23 changes: 23 additions & 0 deletions src/kdtree/trait.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::borrow::Cow;

use geo_traits::{CoordTrait, RectTrait};
use tinyvec::TinyVec;

use crate::indices::Indices;
Expand Down Expand Up @@ -80,6 +81,18 @@ pub trait KDTreeIndex<N: IndexableNum> {
result
}

/// Search the index for items within a given bounding box.
///
/// Returns indices of found items
fn range_rect(&self, rect: &impl RectTrait<T = N>) -> Vec<usize> {
self.range(
rect.min().x(),
rect.min().y(),
rect.max().x(),
rect.max().y(),
)
}

/// Search the index for items within a given radius.
///
/// - qx: x value of query point
Expand Down Expand Up @@ -144,6 +157,16 @@ pub trait KDTreeIndex<N: IndexableNum> {
}
result
}

/// Search the index for items within a given radius.
///
/// - coord: coordinate of query point
/// - r: radius
///
/// Returns indices of found items
fn within_coord(&self, coord: &impl CoordTrait<T = N>, r: N) -> Vec<usize> {
self.within(coord.x(), coord.y(), r)
}
}

impl<N: IndexableNum> KDTreeIndex<N> for KDTreeRef<'_, N> {
Expand Down
18 changes: 17 additions & 1 deletion src/rtree/builder.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use bytemuck::cast_slice_mut;
use geo_traits::{CoordTrait, RectTrait};

use crate::indices::MutableIndices;
use crate::r#type::IndexableNum;
Expand Down Expand Up @@ -73,7 +74,9 @@ impl<N: IndexableNum> RTreeBuilder<N> {
}
}

/// Add a given rectangle to the index.
/// Add a given rectangle to the RTree.
///
/// This returns a positional index that provides a lookup back into the original data.
#[inline]
pub fn add(&mut self, min_x: N, min_y: N, max_x: N, max_y: N) -> usize {
let index = self.pos >> 2;
Expand Down Expand Up @@ -110,6 +113,19 @@ impl<N: IndexableNum> RTreeBuilder<N> {
index
}

/// Add a given rectangle to the RTree.
///
/// This returns a positional index that provides a lookup back into the original data.
#[inline]
pub fn add_rect(&mut self, rect: &impl RectTrait<T = N>) -> usize {
self.add(
rect.min().x(),
rect.min().y(),
rect.max().x(),
rect.max().y(),
)
}

/// Consume this builder, perfoming the sort and generating an RTree ready for queries.
pub fn finish<S: Sort<N>>(mut self) -> OwnedRTree<N> {
assert_eq!(
Expand Down
2 changes: 1 addition & 1 deletion src/rtree/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub(crate) struct TreeMetadata<N: IndexableNum> {
}

impl<N: IndexableNum> TreeMetadata<N> {
pub fn try_new(data: &[u8]) -> Result<Self> {
fn try_new(data: &[u8]) -> Result<Self> {
let magic = data[0];
if magic != 0xfb {
return Err(GeoIndexError::General(
Expand Down
14 changes: 14 additions & 0 deletions src/rtree/trait.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use geo_traits::{CoordTrait, RectTrait};

use crate::error::Result;
use crate::indices::Indices;
use crate::r#type::IndexableNum;
Expand Down Expand Up @@ -97,6 +99,18 @@ pub trait RTreeIndex<N: IndexableNum>: Sized {
results
}

/// Search an RTree given the provided bounding box.
///
/// Results are the indexes of the inserted objects in insertion order.
fn search_rect(&self, rect: &impl RectTrait<T = N>) -> Vec<usize> {
self.search(
rect.min().x(),
rect.min().y(),
rect.max().x(),
rect.max().y(),
)
}

// #[allow(unused_mut, unused_labels, unused_variables)]
// fn neighbors(&self, x: N, y: N, max_distance: Option<N>) -> Vec<usize> {
// let boxes = self.boxes();
Expand Down
Loading