From 687d20b56a6ec38ffe6a3d0bc98e9b6f6afef5fd Mon Sep 17 00:00:00 2001 From: Michael Salib Date: Sun, 13 Nov 2022 13:09:24 -0500 Subject: [PATCH 1/4] dynamic rather than static parameters --- rstar-benches/benches/benchmarks.rs | 23 +-- .../bulk_load/bulk_load_sequential.rs | 28 ++-- .../bulk_load/cluster_group_iterator.rs | 7 +- rstar/src/algorithm/removal.rs | 19 +-- rstar/src/algorithm/rstar.rs | 158 +++++++++--------- rstar/src/lib.rs | 3 +- rstar/src/node.rs | 29 ++-- rstar/src/params.rs | 155 ++++++++--------- rstar/src/rtree.rs | 129 ++++++-------- 9 files changed, 238 insertions(+), 313 deletions(-) diff --git a/rstar-benches/benches/benchmarks.rs b/rstar-benches/benches/benchmarks.rs index 1ccc2c6..189ab80 100644 --- a/rstar-benches/benches/benchmarks.rs +++ b/rstar-benches/benches/benchmarks.rs @@ -8,30 +8,22 @@ extern crate rstar; use rand::{Rng, SeedableRng}; use rand_hc::Hc128Rng; -use rstar::{RStarInsertionStrategy, RTree, RTreeParams}; +use rstar::{Params, RTree}; use criterion::Criterion; const SEED_1: &[u8; 32] = b"Gv0aHMtHkBGsUXNspGU9fLRuCWkZWHZx"; const SEED_2: &[u8; 32] = b"km7DO4GeaFZfTcDXVpnO7ZJlgUY7hZiS"; -struct Params; - -impl RTreeParams for Params { - const MIN_SIZE: usize = 2; - const MAX_SIZE: usize = 40; - const REINSERTION_COUNT: usize = 1; - type DefaultInsertionStrategy = RStarInsertionStrategy; -} - const DEFAULT_BENCHMARK_TREE_SIZE: usize = 2000; fn bulk_load_baseline(c: &mut Criterion) { + let params = Params::new(2, 40, 1); c.bench_function("Bulk load baseline", move |b| { let points: Vec<_> = create_random_points(DEFAULT_BENCHMARK_TREE_SIZE, SEED_1); b.iter(|| { - RTree::<_, Params>::bulk_load_with_params(points.clone()); + RTree::<_>::bulk_load_with_params(params, points.clone()); }); }); } @@ -54,7 +46,8 @@ fn bulk_load_comparison(c: &mut Criterion) { fn tree_creation_quality(c: &mut Criterion) { const SIZE: usize = 100_000; let points: Vec<_> = create_random_points(SIZE, SEED_1); - let tree_bulk_loaded = RTree::<_, Params>::bulk_load_with_params(points.clone()); + let params = Params::new(2, 40, 1); + let tree_bulk_loaded = RTree::<_>::bulk_load_with_params(params.clone(), points.clone()); let mut tree_sequential = RTree::new(); for point in &points { tree_sequential.insert(*point); @@ -81,7 +74,8 @@ fn tree_creation_quality(c: &mut Criterion) { fn locate_successful(c: &mut Criterion) { let points: Vec<_> = create_random_points(100_000, SEED_1); let query_point = points[500]; - let tree = RTree::<_, Params>::bulk_load_with_params(points); + let params = Params::new(2, 40, 1); + let tree = RTree::<_>::bulk_load_with_params(params, points); c.bench_function("locate_at_point (successful)", move |b| { b.iter(|| tree.locate_at_point(&query_point).is_some()) }); @@ -89,7 +83,8 @@ fn locate_successful(c: &mut Criterion) { fn locate_unsuccessful(c: &mut Criterion) { let points: Vec<_> = create_random_points(100_000, SEED_1); - let tree = RTree::<_, Params>::bulk_load_with_params(points); + let params = Params::new(2, 40, 1); + let tree = RTree::<_>::bulk_load_with_params(params, points); let query_point = [0.7, 0.7]; c.bench_function("locate_at_point (unsuccessful)", move |b| { b.iter(|| tree.locate_at_point(&query_point).is_none()) diff --git a/rstar/src/algorithm/bulk_load/bulk_load_sequential.rs b/rstar/src/algorithm/bulk_load/bulk_load_sequential.rs index 886cf8c..46fac1c 100644 --- a/rstar/src/algorithm/bulk_load/bulk_load_sequential.rs +++ b/rstar/src/algorithm/bulk_load/bulk_load_sequential.rs @@ -1,7 +1,7 @@ use crate::envelope::Envelope; use crate::node::{ParentNode, RTreeNode}; use crate::object::RTreeObject; -use crate::params::RTreeParams; +use crate::params::Params; use crate::point::Point; use alloc::{vec, vec::Vec}; @@ -11,29 +11,28 @@ use num_traits::Float; use super::cluster_group_iterator::{calculate_number_of_clusters_on_axis, ClusterGroupIterator}; -fn bulk_load_recursive(elements: Vec, depth: usize) -> ParentNode +fn bulk_load_recursive(params: &Params, elements: Vec, depth: usize) -> ParentNode where T: RTreeObject, ::Point: Point, - Params: RTreeParams, { - let m = Params::MAX_SIZE; + let m = params.max_size(); if elements.len() <= m { // Reached leaf level let elements: Vec<_> = elements.into_iter().map(RTreeNode::Leaf).collect(); return ParentNode::new_parent(elements); } let number_of_clusters_on_axis = - calculate_number_of_clusters_on_axis::(elements.len()); + calculate_number_of_clusters_on_axis::(params, elements.len()); - let iterator = PartitioningTask::<_, Params> { + let iterator = PartitioningTask::<_> { number_of_clusters_on_axis, depth, work_queue: vec![PartitioningState { current_axis: ::Point::DIMENSIONS, elements, }], - _params: Default::default(), + params: params.clone(), }; ParentNode::new_parent(iterator.collect()) } @@ -48,14 +47,14 @@ struct PartitioningState { } /// Successively partitions the given elements into cluster groups and finally into clusters. -struct PartitioningTask { +struct PartitioningTask { work_queue: Vec>, depth: usize, number_of_clusters_on_axis: usize, - _params: core::marker::PhantomData, + params: Params, } -impl Iterator for PartitioningTask { +impl Iterator for PartitioningTask { type Item = RTreeNode; fn next(&mut self) -> Option { @@ -66,7 +65,7 @@ impl Iterator for PartitioningTask(elements, self.depth - 1); + let data = bulk_load_recursive::<_>(&self.params, elements, self.depth - 1); return RTreeNode::Parent(data).into(); } else { // The cluster group needs to be partitioned further along the next axis @@ -89,15 +88,14 @@ impl Iterator for PartitioningTask(elements: Vec) -> ParentNode +pub fn bulk_load_sequential(params: &Params, elements: Vec) -> ParentNode where T: RTreeObject, ::Point: Point, - Params: RTreeParams, { - let m = Params::MAX_SIZE; + let m = params.max_size(); let depth = (elements.len() as f32).log(m as f32).ceil() as usize; - bulk_load_recursive::<_, Params>(elements, depth) + bulk_load_recursive::<_>(params, elements, depth) } #[cfg(test)] diff --git a/rstar/src/algorithm/bulk_load/cluster_group_iterator.rs b/rstar/src/algorithm/bulk_load/cluster_group_iterator.rs index 2b60838..ce26fc8 100644 --- a/rstar/src/algorithm/bulk_load/cluster_group_iterator.rs +++ b/rstar/src/algorithm/bulk_load/cluster_group_iterator.rs @@ -1,4 +1,4 @@ -use crate::{Envelope, Point, RTreeObject, RTreeParams}; +use crate::{Envelope, Params, Point, RTreeObject}; use alloc::vec::Vec; @@ -47,12 +47,11 @@ impl Iterator for ClusterGroupIterator { /// Calculates the desired number of clusters on any axis /// /// A 'cluster' refers to a set of elements that will finally form an rtree node. -pub fn calculate_number_of_clusters_on_axis(number_of_elements: usize) -> usize +pub fn calculate_number_of_clusters_on_axis(params: &Params, number_of_elements: usize) -> usize where T: RTreeObject, - Params: RTreeParams, { - let max_size = Params::MAX_SIZE as f32; + let max_size = params.max_size() as f32; // The depth of the resulting tree, assuming all leaf nodes will be filled up to MAX_SIZE let depth = (number_of_elements as f32).log(max_size).ceil() as usize; // The number of elements each subtree will hold diff --git a/rstar/src/algorithm/removal.rs b/rstar/src/algorithm/removal.rs index 72f9737..246e516 100644 --- a/rstar/src/algorithm/removal.rs +++ b/rstar/src/algorithm/removal.rs @@ -3,7 +3,6 @@ use core::mem::replace; use crate::algorithm::selection_functions::SelectionFunction; use crate::node::{ParentNode, RTreeNode}; use crate::object::RTreeObject; -use crate::params::RTreeParams; use crate::{Envelope, RTree}; use alloc::{vec, vec::Vec}; @@ -24,25 +23,23 @@ use num_traits::Float; /// the yielded values (this behaviour is unlike `Vec::drain_*`). Leaking /// this iterator leads to a leak amplification where all elements of the /// tree are leaked. -pub struct DrainIterator<'a, T, R, Params> +pub struct DrainIterator<'a, T, R> where T: RTreeObject, - Params: RTreeParams, R: SelectionFunction, { node_stack: Vec<(ParentNode, usize, usize)>, removal_function: R, - rtree: &'a mut RTree, + rtree: &'a mut RTree, original_size: usize, } -impl<'a, T, R, Params> DrainIterator<'a, T, R, Params> +impl<'a, T, R> DrainIterator<'a, T, R> where T: RTreeObject, - Params: RTreeParams, R: SelectionFunction, { - pub(crate) fn new(rtree: &'a mut RTree, removal_function: R) -> Self { + pub(crate) fn new(rtree: &'a mut RTree, removal_function: R) -> Self { // We replace with a root as a brand new RTree in case the iterator is // `mem::forgot`ten. @@ -57,7 +54,7 @@ where ); let original_size = replace(rtree.size_mut(), 0); - let m = Params::MIN_SIZE; + let m = rtree.params.min_size(); let max_depth = (original_size as f32).log(m.max(2) as f32).ceil() as usize; let mut node_stack = Vec::with_capacity(max_depth); node_stack.push((root, 0, 0)); @@ -120,10 +117,9 @@ where } } -impl<'a, T, R, Params> Iterator for DrainIterator<'a, T, R, Params> +impl<'a, T, R> Iterator for DrainIterator<'a, T, R> where T: RTreeObject, - Params: RTreeParams, R: SelectionFunction, { type Item = T; @@ -180,10 +176,9 @@ where } } -impl<'a, T, R, Params> Drop for DrainIterator<'a, T, R, Params> +impl<'a, T, R> Drop for DrainIterator<'a, T, R> where T: RTreeObject, - Params: RTreeParams, R: SelectionFunction, { fn drop(&mut self) { diff --git a/rstar/src/algorithm/rstar.rs b/rstar/src/algorithm/rstar.rs index 481fd5f..86ca4f3 100644 --- a/rstar/src/algorithm/rstar.rs +++ b/rstar/src/algorithm/rstar.rs @@ -1,13 +1,22 @@ use crate::envelope::Envelope; use crate::node::{envelope_for_children, ParentNode, RTreeNode}; use crate::object::RTreeObject; -use crate::params::{InsertionStrategy, RTreeParams}; +use crate::params::Params; use crate::point::{Point, PointExt}; use crate::rtree::RTree; use alloc::vec::Vec; use num_traits::{Bounded, Zero}; +enum InsertionResult +where + T: RTreeObject, +{ + Split(RTreeNode), + Reinsert(Vec>, usize), + Complete, +} + /// Inserts points according to the r-star heuristic. /// /// The r*-heuristic focusses on good insertion quality at the costs of @@ -16,78 +25,65 @@ use num_traits::{Bounded, Zero}; /// /// `RStarInsertionStrategy` is used as the default insertion strategy. /// See [InsertionStrategy] for more information on insertion strategies. -pub enum RStarInsertionStrategy {} - -enum InsertionResult +pub fn rstar_insert(tree: &mut RTree, t: T) where T: RTreeObject, { - Split(RTreeNode), - Reinsert(Vec>, usize), - Complete, -} + use InsertionAction::*; -impl InsertionStrategy for RStarInsertionStrategy { - fn insert(tree: &mut RTree, t: T) - where - Params: RTreeParams, - T: RTreeObject, - { - use InsertionAction::*; + enum InsertionAction { + PerformSplit(RTreeNode), + PerformReinsert(RTreeNode), + } - enum InsertionAction { - PerformSplit(RTreeNode), - PerformReinsert(RTreeNode), + let first = recursive_insert::<_>(&tree.params.clone(), tree.root_mut(), RTreeNode::Leaf(t), 0); + let mut target_height = 0; + let mut insertion_stack = Vec::new(); + match first { + InsertionResult::Split(node) => insertion_stack.push(PerformSplit(node)), + InsertionResult::Reinsert(nodes_to_reinsert, real_target_height) => { + insertion_stack.extend(nodes_to_reinsert.into_iter().map(PerformReinsert)); + target_height = real_target_height; } + InsertionResult::Complete => {} + }; - let first = recursive_insert::<_, Params>(tree.root_mut(), RTreeNode::Leaf(t), 0); - let mut target_height = 0; - let mut insertion_stack = Vec::new(); - match first { - InsertionResult::Split(node) => insertion_stack.push(PerformSplit(node)), - InsertionResult::Reinsert(nodes_to_reinsert, real_target_height) => { - insertion_stack.extend(nodes_to_reinsert.into_iter().map(PerformReinsert)); - target_height = real_target_height; + while let Some(next) = insertion_stack.pop() { + match next { + PerformSplit(node) => { + // The root node was split, create a new root and increase height + let new_root = ParentNode::new_root(&tree.params); + let old_root = ::core::mem::replace(tree.root_mut(), new_root); + let new_envelope = old_root.envelope.merged(&node.envelope()); + let root = tree.root_mut(); + root.envelope = new_envelope; + root.children.push(RTreeNode::Parent(old_root)); + root.children.push(node); + target_height += 1; } - InsertionResult::Complete => {} - }; - - while let Some(next) = insertion_stack.pop() { - match next { - PerformSplit(node) => { - // The root node was split, create a new root and increase height - let new_root = ParentNode::new_root::(); - let old_root = ::core::mem::replace(tree.root_mut(), new_root); - let new_envelope = old_root.envelope.merged(&node.envelope()); - let root = tree.root_mut(); - root.envelope = new_envelope; - root.children.push(RTreeNode::Parent(old_root)); - root.children.push(node); - target_height += 1; - } - PerformReinsert(node_to_reinsert) => { - let root = tree.root_mut(); - match forced_insertion::(root, node_to_reinsert, target_height) { - InsertionResult::Split(node) => insertion_stack.push(PerformSplit(node)), - InsertionResult::Reinsert(_, _) => { - panic!("Unexpected reinsert. This is a bug in rstar.") - } - InsertionResult::Complete => {} + PerformReinsert(node_to_reinsert) => { + let params = tree.params.clone(); + let root = tree.root_mut(); + match forced_insertion::(¶ms, root, node_to_reinsert, target_height) { + InsertionResult::Split(node) => insertion_stack.push(PerformSplit(node)), + InsertionResult::Reinsert(_, _) => { + panic!("Unexpected reinsert. This is a bug in rstar.") } + InsertionResult::Complete => {} } } } } } -fn forced_insertion( +fn forced_insertion( + params: &Params, node: &mut ParentNode, t: RTreeNode, target_height: usize, ) -> InsertionResult where T: RTreeObject, - Params: RTreeParams, { node.envelope.merge(&t.envelope()); let expand_index = choose_subtree(node, &t); @@ -95,15 +91,15 @@ where if target_height == 0 || node.children.len() < expand_index { // Force insertion into this node node.children.push(t); - return resolve_overflow_without_reinsertion::<_, Params>(node); + return resolve_overflow_without_reinsertion::<_>(params, node); } if let RTreeNode::Parent(ref mut follow) = node.children[expand_index] { - match forced_insertion::<_, Params>(follow, t, target_height - 1) { + match forced_insertion::<_>(params, follow, t, target_height - 1) { InsertionResult::Split(child) => { node.envelope.merge(&child.envelope()); node.children.push(child); - resolve_overflow_without_reinsertion::<_, Params>(node) + resolve_overflow_without_reinsertion::<_>(params, node) } other => other, } @@ -112,14 +108,14 @@ where } } -fn recursive_insert( +fn recursive_insert( + params: &Params, node: &mut ParentNode, t: RTreeNode, current_height: usize, ) -> InsertionResult where T: RTreeObject, - Params: RTreeParams, { node.envelope.merge(&t.envelope()); let expand_index = choose_subtree(node, &t); @@ -127,11 +123,11 @@ where if node.children.len() < expand_index { // Force insertion into this node node.children.push(t); - return resolve_overflow::<_, Params>(node, current_height); + return resolve_overflow::<_>(params, node, current_height); } let expand = if let RTreeNode::Parent(ref mut follow) = node.children[expand_index] { - recursive_insert::<_, Params>(follow, t, current_height + 1) + recursive_insert::<_>(params, follow, t, current_height + 1) } else { panic!("This is a bug in rstar.") }; @@ -140,7 +136,7 @@ where InsertionResult::Split(child) => { node.envelope.merge(&child.envelope()); node.children.push(child); - resolve_overflow::<_, Params>(node, current_height) + resolve_overflow::<_>(params, node, current_height) } InsertionResult::Reinsert(a, b) => { node.envelope = envelope_for_children(&node.children); @@ -220,46 +216,50 @@ where } // Never returns a request for reinsertion -fn resolve_overflow_without_reinsertion(node: &mut ParentNode) -> InsertionResult +fn resolve_overflow_without_reinsertion( + params: &Params, + node: &mut ParentNode, +) -> InsertionResult where T: RTreeObject, - Params: RTreeParams, { - if node.children.len() > Params::MAX_SIZE { - let off_split = split::<_, Params>(node); + if node.children.len() > params.max_size() { + let off_split = split::<_>(params, node); InsertionResult::Split(off_split) } else { InsertionResult::Complete } } -fn resolve_overflow(node: &mut ParentNode, current_depth: usize) -> InsertionResult +fn resolve_overflow( + params: &Params, + node: &mut ParentNode, + current_depth: usize, +) -> InsertionResult where T: RTreeObject, - Params: RTreeParams, { - if Params::REINSERTION_COUNT == 0 { - resolve_overflow_without_reinsertion::<_, Params>(node) - } else if node.children.len() > Params::MAX_SIZE { - let nodes_for_reinsertion = get_nodes_for_reinsertion::<_, Params>(node); + if params.reinsertion_count() == 0 { + resolve_overflow_without_reinsertion::<_>(params, node) + } else if node.children.len() > params.max_size() { + let nodes_for_reinsertion = get_nodes_for_reinsertion::<_>(params, node); InsertionResult::Reinsert(nodes_for_reinsertion, current_depth) } else { InsertionResult::Complete } } -fn split(node: &mut ParentNode) -> RTreeNode +fn split(params: &Params, node: &mut ParentNode) -> RTreeNode where T: RTreeObject, - Params: RTreeParams, { - let axis = get_split_axis::<_, Params>(node); + let axis = get_split_axis::<_>(params, node); let zero = <::Point as Point>::Scalar::zero(); debug_assert!(node.children.len() >= 2); // Sort along axis T::Envelope::sort_envelopes(axis, &mut node.children); let mut best = (zero, zero); - let min_size = Params::MIN_SIZE; + let min_size = params.min_size(); let mut best_index = min_size; for k in min_size..=node.children.len() - min_size { @@ -286,14 +286,13 @@ where RTreeNode::Parent(ParentNode::new_parent(off_split)) } -fn get_split_axis(node: &mut ParentNode) -> usize +fn get_split_axis(params: &Params, node: &mut ParentNode) -> usize where T: RTreeObject, - Params: RTreeParams, { let mut best_goodness = <::Point as Point>::Scalar::max_value(); let mut best_axis = 0; - let min_size = Params::MIN_SIZE; + let min_size = params.min_size(); let until = node.children.len() - min_size + 1; for axis in 0..::Point::DIMENSIONS { // Sort children along the current axis @@ -328,10 +327,9 @@ where best_axis } -fn get_nodes_for_reinsertion(node: &mut ParentNode) -> Vec> +fn get_nodes_for_reinsertion(params: &Params, node: &mut ParentNode) -> Vec> where T: RTreeObject, - Params: RTreeParams, { let center = node.envelope.center(); // Sort with increasing order so we can use Vec::split_off @@ -347,7 +345,7 @@ where let num_children = node.children.len(); let result = node .children - .split_off(num_children - Params::REINSERTION_COUNT); + .split_off(num_children - params.reinsertion_count()); node.envelope = envelope_for_children(&node.children); result } diff --git a/rstar/src/lib.rs b/rstar/src/lib.rs index 53a7cda..e9b128b 100644 --- a/rstar/src/lib.rs +++ b/rstar/src/lib.rs @@ -39,12 +39,11 @@ mod rtree; mod test_utilities; pub use crate::aabb::AABB; -pub use crate::algorithm::rstar::RStarInsertionStrategy; pub use crate::algorithm::selection_functions::SelectionFunction; pub use crate::envelope::Envelope; pub use crate::node::{ParentNode, RTreeNode}; pub use crate::object::{PointDistance, RTreeObject}; -pub use crate::params::{DefaultParams, InsertionStrategy, RTreeParams}; +pub use crate::params::Params; pub use crate::point::{Point, RTreeNum}; pub use crate::rtree::RTree; diff --git a/rstar/src/node.rs b/rstar/src/node.rs index 6aa6adf..477e10e 100644 --- a/rstar/src/node.rs +++ b/rstar/src/node.rs @@ -1,6 +1,6 @@ use crate::envelope::Envelope; use crate::object::RTreeObject; -use crate::params::RTreeParams; +use crate::params::Params; use alloc::vec::Vec; @@ -85,13 +85,10 @@ where self.envelope } - pub(crate) fn new_root() -> Self - where - Params: RTreeParams, - { + pub(crate) fn new_root(params: &Params) -> Self { ParentNode { envelope: Envelope::new_empty(), - children: Vec::with_capacity(Params::MAX_SIZE + 1), + children: Vec::with_capacity(params.max_size() + 1), } } @@ -102,35 +99,31 @@ where } #[cfg(test)] - pub fn sanity_check(&self, check_max_size: bool) -> Option - where - Params: RTreeParams, - { + pub fn sanity_check(&self, params: &Params, check_max_size: bool) -> Option { if self.children.is_empty() { Some(0) } else { let mut result = None; - self.sanity_check_inner::(check_max_size, 1, &mut result); + self.sanity_check_inner(params, check_max_size, 1, &mut result); result } } #[cfg(test)] - fn sanity_check_inner( + fn sanity_check_inner( &self, + params: &Params, check_max_size: bool, height: usize, leaf_height: &mut Option, - ) where - Params: RTreeParams, - { + ) { if height > 1 { - let min_size = Params::MIN_SIZE; + let min_size = params.min_size(); assert!(self.children.len() >= min_size); } let mut envelope = T::Envelope::new_empty(); if check_max_size { - let max_size = Params::MAX_SIZE; + let max_size = params.max_size(); assert!(self.children.len() <= max_size); } @@ -146,7 +139,7 @@ where } RTreeNode::Parent(ref data) => { envelope.merge(&data.envelope); - data.sanity_check_inner::(check_max_size, height + 1, leaf_height); + data.sanity_check_inner(params, check_max_size, height + 1, leaf_height); } } } diff --git a/rstar/src/params.rs b/rstar/src/params.rs index 64c0e66..63c4ca4 100644 --- a/rstar/src/params.rs +++ b/rstar/src/params.rs @@ -1,5 +1,4 @@ -use crate::algorithm::rstar::RStarInsertionStrategy; -use crate::{Envelope, Point, RTree, RTreeObject}; +use crate::{Envelope, Point, RTreeObject}; /// Defines static parameters for an r-tree. /// @@ -8,109 +7,91 @@ use crate::{Envelope, Point, RTree, RTreeObject}; /// /// # Example /// ``` -/// use rstar::{RTreeParams, RTree, RStarInsertionStrategy}; -/// +/// use rstar::{Params, RTree}; /// // This example uses an rtree with larger internal nodes. -/// struct LargeNodeParameters; -/// -/// impl RTreeParams for LargeNodeParameters -/// { -/// const MIN_SIZE: usize = 10; -/// const MAX_SIZE: usize = 30; -/// const REINSERTION_COUNT: usize = 5; -/// type DefaultInsertionStrategy = RStarInsertionStrategy; -/// } -/// -/// // Optional but helpful: Define a type alias for the new r-tree -/// type LargeNodeRTree = RTree; /// /// # fn main() { /// // The only difference from now on is the usage of "new_with_params" instead of "new" -/// let mut large_node_tree: LargeNodeRTree<_> = RTree::new_with_params(); +/// let params = Params::new(10, 30, 5); +/// let mut large_node_tree: RTree<_> = RTree::new_with_params(params.clone()); /// // Using the r-tree should allow inference for the point type /// large_node_tree.insert([1.0, -1.0f32]); /// // There is also a bulk load method with parameters: /// # let some_elements = vec![[0.0, 0.0]]; -/// let tree: LargeNodeRTree<_> = RTree::bulk_load_with_params(some_elements); +/// let tree: RTree<_> = RTree::bulk_load_with_params(params, some_elements); /// # } /// ``` -pub trait RTreeParams: Send + Sync { - /// The minimum size of an internal node. `MIN_SIZE` must be greater than zero, and up to half - /// as large as `MAX_SIZE`. - /// - /// Choosing a value around one half or one third of `MAX_SIZE` is recommended. Larger values - /// should yield slightly better tree quality, while lower values may benefit insertion - /// performance. - const MIN_SIZE: usize; - - /// The maximum size of an internal node. Larger values will improve insertion performance - /// but increase the average query time. - const MAX_SIZE: usize; - /// The number of nodes that the insertion strategy tries to occasionally reinsert to - /// maintain a good tree quality. Must be smaller than `MAX_SIZE` - `MIN_SIZE`. - /// Larger values will improve query times but increase insertion time. - const REINSERTION_COUNT: usize; +/// hi +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct Params { + min_size: usize, + max_size: usize, + reinsertion_count: usize, +} - /// The insertion strategy which is used when calling [RTree::insert]. - type DefaultInsertionStrategy: InsertionStrategy; +impl Default for Params { + fn default() -> Self { + Self { + min_size: 3, + max_size: 6, + reinsertion_count: 2, + } + } } -/// The default parameters used when creating an r-tree without specific parameters. -#[derive(Clone, Copy, PartialEq, Eq)] -pub struct DefaultParams; +impl Params { + /// hi + pub fn new(min_size: usize, max_size: usize, reinsertion_count: usize) -> Self { + Params { + min_size, + max_size, + reinsertion_count, + } + } -impl RTreeParams for DefaultParams { - const MIN_SIZE: usize = 3; - const MAX_SIZE: usize = 6; - const REINSERTION_COUNT: usize = 2; - type DefaultInsertionStrategy = RStarInsertionStrategy; -} + /// hi + pub fn min_size(&self) -> usize { + self.min_size + } -/// Defines how points are inserted into an r-tree. -/// -/// Different strategies try to minimize both _insertion time_ (how long does it take to add a new -/// object into the tree?) and _querying time_ (how long does an average nearest neighbor query -/// take?). -/// Currently, only one insertion strategy is implemented: R* (R-star) insertion. R* insertion -/// tries to minimize querying performance while yielding reasonable insertion times, making it a -/// good default strategy. More strategies may be implemented in the future. -/// -/// Only calls to [RTree::insert] are affected by this strategy. -/// -/// This trait is not meant to be implemented by the user. -pub trait InsertionStrategy { - #[doc(hidden)] - fn insert(tree: &mut RTree, t: T) - where - Params: RTreeParams, - T: RTreeObject; -} + /// hi + pub fn max_size(&self) -> usize { + self.max_size + } + + /// hi + pub fn reinsertion_count(&self) -> usize { + self.reinsertion_count + } -pub fn verify_parameters() { - assert!( - P::MAX_SIZE >= 4, - "MAX_SIZE too small. Must be larger than 4." - ); + /// hi + pub fn check(&self) { + assert!( + self.max_size() >= 4, + "MAX_SIZE too small. Must be larger than 4." + ); - assert!(P::MIN_SIZE > 0, "MIN_SIZE must be at least 1",); - let max_min_size = (P::MAX_SIZE + 1) / 2; - assert!( - P::MIN_SIZE <= max_min_size, - "MIN_SIZE too large. Must be less or equal to {:?}", - max_min_size - ); + assert!(self.min_size() > 0, "MIN_SIZE must be at least 1",); + let max_min_size = (self.max_size() + 1) / 2; + assert!( + self.min_size() <= max_min_size, + "MIN_SIZE too large. Must be less or equal to {:?}", + max_min_size + ); - let max_reinsertion_count = P::MAX_SIZE - P::MIN_SIZE; - assert!( - P::REINSERTION_COUNT < max_reinsertion_count, - "REINSERTION_COUNT too large. Must be smaller than {:?}", - max_reinsertion_count - ); + let max_reinsertion_count = self.max_size() - self.min_size(); + assert!( + self.reinsertion_count() < max_reinsertion_count, + "REINSERTION_COUNT too large. Must be smaller than {:?}", + max_reinsertion_count + ); - let dimension = ::Point::DIMENSIONS; - assert!( - dimension > 1, - "Point dimension too small - must be at least 2" - ); + let dimension = ::Point::DIMENSIONS; + assert!( + dimension > 1, + "Point dimension too small - must be at least 2" + ); + } } diff --git a/rstar/src/rtree.rs b/rstar/src/rtree.rs index 2182fb1..2427c95 100644 --- a/rstar/src/rtree.rs +++ b/rstar/src/rtree.rs @@ -6,11 +6,12 @@ use crate::algorithm::nearest_neighbor::NearestNeighborDistance2Iterator; use crate::algorithm::nearest_neighbor::NearestNeighborIterator; use crate::algorithm::removal; use crate::algorithm::removal::DrainIterator; +use crate::algorithm::rstar::rstar_insert; use crate::algorithm::selection_functions::*; use crate::envelope::Envelope; use crate::node::ParentNode; use crate::object::{PointDistance, RTreeObject}; -use crate::params::{verify_parameters, DefaultParams, InsertionStrategy, RTreeParams}; +use crate::params::Params; use crate::Point; use alloc::vec::Vec; @@ -18,13 +19,12 @@ use alloc::vec::Vec; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -impl Default for RTree +impl Default for RTree where T: RTreeObject, - Params: RTreeParams, { fn default() -> Self { - Self::new_with_params() + Self::new_with_params(Params::default()) } } @@ -98,11 +98,10 @@ where /// If a library defines a method that should be generic over the r-tree type signature, make /// sure to include both type parameters like this: /// ``` -/// # use rstar::{RTree,RTreeObject, RTreeParams}; -/// pub fn generic_rtree_function(tree: &mut RTree) +/// # use rstar::{RTree, RTreeObject}; +/// pub fn generic_rtree_function(tree: &mut RTree) /// where -/// T: RTreeObject, -/// Params: RTreeParams +/// T: RTreeObject /// { /// // ... /// } @@ -143,37 +142,33 @@ where deserialize = "T: Deserialize<'de>, T::Envelope: Deserialize<'de>" )) )] -pub struct RTree +pub struct RTree where - Params: RTreeParams, T: RTreeObject, { root: ParentNode, size: usize, - _params: ::core::marker::PhantomData, + pub(crate) params: Params, } -struct DebugHelper<'a, T, Params> +struct DebugHelper<'a, T> where T: RTreeObject + ::core::fmt::Debug + 'a, - Params: RTreeParams + 'a, { - rtree: &'a RTree, + rtree: &'a RTree, } -impl<'a, T, Params> ::core::fmt::Debug for DebugHelper<'a, T, Params> +impl<'a, T> ::core::fmt::Debug for DebugHelper<'a, T> where T: RTreeObject + ::core::fmt::Debug, - Params: RTreeParams, { fn fmt(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { formatter.debug_set().entries(self.rtree.iter()).finish() } } -impl ::core::fmt::Debug for RTree +impl ::core::fmt::Debug for RTree where - Params: RTreeParams, T: RTreeObject + ::core::fmt::Debug, { fn fmt(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { @@ -193,7 +188,7 @@ where /// /// The created r-tree is configured with [default parameters](DefaultParams). pub fn new() -> Self { - Self::new_with_params() + Self::new_with_params(Params::default()) } /// Creates a new r-tree with some elements already inserted. @@ -209,25 +204,24 @@ where /// Bulk loading runs in `O(n * log(n))`, where `n` is the number of loaded /// elements. pub fn bulk_load(elements: Vec) -> Self { - Self::bulk_load_with_params(elements) + Self::bulk_load_with_params(Params::default(), elements) } } -impl RTree +impl RTree where - Params: RTreeParams, T: RTreeObject, { /// Creates a new, empty r-tree. /// /// The tree's compile time parameters must be specified. Refer to the /// [RTreeParams] trait for more information and a usage example. - pub fn new_with_params() -> Self { - verify_parameters::(); + pub fn new_with_params(params: Params) -> Self { + params.check::(); RTree { - root: ParentNode::new_root::(), + root: ParentNode::new_root(¶ms), size: 0, - _params: Default::default(), + params, } } @@ -235,8 +229,8 @@ where /// /// For more information refer to [RTree::bulk_load] /// and [RTreeParams]. - pub fn bulk_load_with_params(elements: Vec) -> Self { - Self::new_from_bulk_loading(elements, bulk_load::bulk_load_sequential::<_, Params>) + pub fn bulk_load_with_params(params: Params, elements: Vec) -> Self { + Self::new_from_bulk_loading(params, elements, bulk_load::bulk_load_sequential::<_>) } /// Returns the number of objects in an r-tree. @@ -326,7 +320,7 @@ where /// See /// [drain_with_selection_function](#method.drain_with_selection_function) /// for more information. - pub fn drain(&mut self) -> DrainIterator { + pub fn drain(&mut self) -> DrainIterator { self.drain_with_selection_function(SelectAllFunc) } @@ -334,7 +328,7 @@ where pub fn drain_in_envelope( &mut self, envelope: T::Envelope, - ) -> DrainIterator, Params> { + ) -> DrainIterator> { let sel = SelectInEnvelopeFunction::new(envelope); self.drain_with_selection_function(sel) } @@ -445,21 +439,18 @@ where } fn new_from_bulk_loading( + params: Params, elements: Vec, - root_loader: impl Fn(Vec) -> ParentNode, + root_loader: impl Fn(&Params, Vec) -> ParentNode, ) -> Self { - verify_parameters::(); + params.check::(); let size = elements.len(); let root = if size == 0 { - ParentNode::new_root::() + ParentNode::new_root(¶ms) } else { - root_loader(elements) + root_loader(¶ms, elements) }; - RTree { - root, - size, - _params: Default::default(), - } + RTree { root, size, params } } /// Removes and returns a single element from the tree. The element to remove is specified @@ -486,7 +477,7 @@ where /// iteration would stop the removal. However, the returned iterator /// must be properly dropped. Leaking this iterator leads to a leak /// amplification, where all the elements in the tree are leaked. - pub fn drain_with_selection_function(&mut self, function: F) -> DrainIterator + pub fn drain_with_selection_function(&mut self, function: F) -> DrainIterator where F: SelectionFunction, { @@ -499,15 +490,14 @@ where pub fn drain_in_envelope_intersecting( &mut self, envelope: T::Envelope, - ) -> DrainIterator, Params> { + ) -> DrainIterator> { let selection_function = SelectInEnvelopeFuncIntersecting::new(envelope); self.drain_with_selection_function(selection_function) } } -impl RTree +impl RTree where - Params: RTreeParams, T: PointDistance, { /// Returns a single object that covers a given point. @@ -586,9 +576,8 @@ where } } -impl RTree +impl RTree where - Params: RTreeParams, T: RTreeObject + PartialEq, { /// Returns `true` if a given element is equal (`==`) to an element in the @@ -636,9 +625,8 @@ where } } -impl RTree +impl RTree where - Params: RTreeParams, T: PointDistance, { /// Returns the nearest neighbor for a given point. @@ -715,7 +703,7 @@ where &mut self, query_point: ::Point, max_squared_radius: <::Point as Point>::Scalar, - ) -> DrainIterator, Params> { + ) -> DrainIterator> { let selection_function = SelectWithinDistanceFunction::new(query_point, max_squared_radius); self.drain_with_selection_function(selection_function) } @@ -798,10 +786,9 @@ where } } -impl RTree +impl RTree where T: RTreeObject, - Params: RTreeParams, { /// Inserts a new element into the r-tree. /// @@ -812,23 +799,21 @@ where /// The [r-tree documentation](RTree) contains more information about /// r-tree performance. pub fn insert(&mut self, t: T) { - Params::DefaultInsertionStrategy::insert(self, t); + rstar_insert(self, t); self.size += 1; } } -impl RTree +impl RTree where T: RTreeObject, ::Point: Point, - Params: RTreeParams, { } -impl<'a, T, Params> IntoIterator for &'a RTree +impl<'a, T> IntoIterator for &'a RTree where T: RTreeObject, - Params: RTreeParams, { type IntoIter = RTreeIterator<'a, T>; type Item = &'a T; @@ -838,10 +823,9 @@ where } } -impl<'a, T, Params> IntoIterator for &'a mut RTree +impl<'a, T> IntoIterator for &'a mut RTree where T: RTreeObject, - Params: RTreeParams, { type IntoIter = RTreeIteratorMut<'a, T>; type Item = &'a mut T; @@ -854,41 +838,24 @@ where #[cfg(test)] mod test { use super::RTree; - use crate::algorithm::rstar::RStarInsertionStrategy; - use crate::params::RTreeParams; + use crate::params::Params; use crate::test_utilities::{create_random_points, SEED_1}; - use crate::DefaultParams; - - struct TestParams; - impl RTreeParams for TestParams { - const MIN_SIZE: usize = 10; - const MAX_SIZE: usize = 20; - const REINSERTION_COUNT: usize = 1; - type DefaultInsertionStrategy = RStarInsertionStrategy; - } #[test] fn test_remove_capacity() { - pub struct WeirdParams; - - impl RTreeParams for WeirdParams { - const MIN_SIZE: usize = 1; - const MAX_SIZE: usize = 10; - const REINSERTION_COUNT: usize = 1; - type DefaultInsertionStrategy = RStarInsertionStrategy; - } - + let params = Params::new(1, 10, 1); let mut items: Vec<[f32; 2]> = Vec::new(); for i in 0..2 { items.push([i as f32, i as f32]); } - let mut tree: RTree<_, WeirdParams> = RTree::bulk_load_with_params(items); + let mut tree: RTree<_> = RTree::bulk_load_with_params(params, items); assert_eq!(tree.remove(&[1.0, 1.0]).unwrap(), [1.0, 1.0]); } #[test] fn test_create_rtree_with_parameters() { - let tree: RTree<[f32; 2], TestParams> = RTree::new_with_params(); + let params = Params::new(10, 20, 1); + let tree: RTree<[f32; 2]> = RTree::new_with_params(params); assert_eq!(tree.size(), 0); } @@ -908,7 +875,7 @@ mod test { let mut tree = RTree::new(); for p in &points { tree.insert(*p); - tree.root.sanity_check::(true); + tree.root.sanity_check(&tree.params, true); } assert_eq!(tree.size(), NUM_POINTS); for p in &points { @@ -1009,7 +976,7 @@ mod test { // Bulk loading will create nodes larger than Params::MAX_SIZE, // which is intentional and not harmful. tree.insert(node); - tree.root().sanity_check::(false); + tree.root().sanity_check(&tree.params, false); } } } From 5e70ff2f792cf1478be9f1c126d6f0bca885b68b Mon Sep 17 00:00:00 2001 From: Michael Salib Date: Mon, 14 Nov 2022 07:33:46 -0500 Subject: [PATCH 2/4] whee --- .../bulk_load/bulk_load_sequential.rs | 6 +-- .../bulk_load/cluster_group_iterator.rs | 2 +- rstar/src/algorithm/rstar.rs | 22 ++++---- rstar/src/node.rs | 2 +- rstar/src/params.rs | 50 +++++++------------ rstar/src/rtree.rs | 31 +++++++++--- 6 files changed, 60 insertions(+), 53 deletions(-) diff --git a/rstar/src/algorithm/bulk_load/bulk_load_sequential.rs b/rstar/src/algorithm/bulk_load/bulk_load_sequential.rs index 46fac1c..33dcca1 100644 --- a/rstar/src/algorithm/bulk_load/bulk_load_sequential.rs +++ b/rstar/src/algorithm/bulk_load/bulk_load_sequential.rs @@ -11,7 +11,7 @@ use num_traits::Float; use super::cluster_group_iterator::{calculate_number_of_clusters_on_axis, ClusterGroupIterator}; -fn bulk_load_recursive(params: &Params, elements: Vec, depth: usize) -> ParentNode +fn bulk_load_recursive(params: Params, elements: Vec, depth: usize) -> ParentNode where T: RTreeObject, ::Point: Point, @@ -65,7 +65,7 @@ impl Iterator for PartitioningTask { } = next; if current_axis == 0 { // Partitioning finished successfully on all axis. The remaining cluster forms a new node - let data = bulk_load_recursive::<_>(&self.params, elements, self.depth - 1); + let data = bulk_load_recursive::<_>(self.params, elements, self.depth - 1); return RTreeNode::Parent(data).into(); } else { // The cluster group needs to be partitioned further along the next axis @@ -88,7 +88,7 @@ impl Iterator for PartitioningTask { /// A multi dimensional implementation of the OMT bulk loading algorithm. /// /// See http://ceur-ws.org/Vol-74/files/FORUM_18.pdf -pub fn bulk_load_sequential(params: &Params, elements: Vec) -> ParentNode +pub fn bulk_load_sequential(params: Params, elements: Vec) -> ParentNode where T: RTreeObject, ::Point: Point, diff --git a/rstar/src/algorithm/bulk_load/cluster_group_iterator.rs b/rstar/src/algorithm/bulk_load/cluster_group_iterator.rs index ce26fc8..465b621 100644 --- a/rstar/src/algorithm/bulk_load/cluster_group_iterator.rs +++ b/rstar/src/algorithm/bulk_load/cluster_group_iterator.rs @@ -47,7 +47,7 @@ impl Iterator for ClusterGroupIterator { /// Calculates the desired number of clusters on any axis /// /// A 'cluster' refers to a set of elements that will finally form an rtree node. -pub fn calculate_number_of_clusters_on_axis(params: &Params, number_of_elements: usize) -> usize +pub fn calculate_number_of_clusters_on_axis(params: Params, number_of_elements: usize) -> usize where T: RTreeObject, { diff --git a/rstar/src/algorithm/rstar.rs b/rstar/src/algorithm/rstar.rs index 86ca4f3..0847962 100644 --- a/rstar/src/algorithm/rstar.rs +++ b/rstar/src/algorithm/rstar.rs @@ -36,7 +36,8 @@ where PerformReinsert(RTreeNode), } - let first = recursive_insert::<_>(&tree.params.clone(), tree.root_mut(), RTreeNode::Leaf(t), 0); + let params = tree.params.clone(); + let first = recursive_insert::<_>(params, tree.root_mut(), RTreeNode::Leaf(t), 0); let mut target_height = 0; let mut insertion_stack = Vec::new(); match first { @@ -52,7 +53,7 @@ where match next { PerformSplit(node) => { // The root node was split, create a new root and increase height - let new_root = ParentNode::new_root(&tree.params); + let new_root = ParentNode::new_root(tree.params); let old_root = ::core::mem::replace(tree.root_mut(), new_root); let new_envelope = old_root.envelope.merged(&node.envelope()); let root = tree.root_mut(); @@ -62,9 +63,8 @@ where target_height += 1; } PerformReinsert(node_to_reinsert) => { - let params = tree.params.clone(); let root = tree.root_mut(); - match forced_insertion::(¶ms, root, node_to_reinsert, target_height) { + match forced_insertion::(params, root, node_to_reinsert, target_height) { InsertionResult::Split(node) => insertion_stack.push(PerformSplit(node)), InsertionResult::Reinsert(_, _) => { panic!("Unexpected reinsert. This is a bug in rstar.") @@ -77,7 +77,7 @@ where } fn forced_insertion( - params: &Params, + params: Params, node: &mut ParentNode, t: RTreeNode, target_height: usize, @@ -109,7 +109,7 @@ where } fn recursive_insert( - params: &Params, + params: Params, node: &mut ParentNode, t: RTreeNode, current_height: usize, @@ -217,7 +217,7 @@ where // Never returns a request for reinsertion fn resolve_overflow_without_reinsertion( - params: &Params, + params: Params, node: &mut ParentNode, ) -> InsertionResult where @@ -232,7 +232,7 @@ where } fn resolve_overflow( - params: &Params, + params: Params, node: &mut ParentNode, current_depth: usize, ) -> InsertionResult @@ -249,7 +249,7 @@ where } } -fn split(params: &Params, node: &mut ParentNode) -> RTreeNode +fn split(params: Params, node: &mut ParentNode) -> RTreeNode where T: RTreeObject, { @@ -286,7 +286,7 @@ where RTreeNode::Parent(ParentNode::new_parent(off_split)) } -fn get_split_axis(params: &Params, node: &mut ParentNode) -> usize +fn get_split_axis(params: Params, node: &mut ParentNode) -> usize where T: RTreeObject, { @@ -327,7 +327,7 @@ where best_axis } -fn get_nodes_for_reinsertion(params: &Params, node: &mut ParentNode) -> Vec> +fn get_nodes_for_reinsertion(params: Params, node: &mut ParentNode) -> Vec> where T: RTreeObject, { diff --git a/rstar/src/node.rs b/rstar/src/node.rs index 477e10e..01e61df 100644 --- a/rstar/src/node.rs +++ b/rstar/src/node.rs @@ -85,7 +85,7 @@ where self.envelope } - pub(crate) fn new_root(params: &Params) -> Self { + pub(crate) fn new_root(params: Params) -> Self { ParentNode { envelope: Envelope::new_empty(), children: Vec::with_capacity(params.max_size() + 1), diff --git a/rstar/src/params.rs b/rstar/src/params.rs index 63c4ca4..ba1bbb1 100644 --- a/rstar/src/params.rs +++ b/rstar/src/params.rs @@ -1,5 +1,3 @@ -use crate::{Envelope, Point, RTreeObject}; - /// Defines static parameters for an r-tree. /// /// Internally, an r-tree contains several nodes, similar to a b-tree. These parameters change @@ -44,6 +42,25 @@ impl Default for Params { impl Params { /// hi pub fn new(min_size: usize, max_size: usize, reinsertion_count: usize) -> Self { + // FIXME: add an Error enum and make this function return + // Result instead of asserting.... + assert!(max_size >= 4, "MAX_SIZE too small. Must be larger than 4."); + + assert!(min_size > 0, "MIN_SIZE must be at least 1",); + let max_min_size = (max_size + 1) / 2; + assert!( + min_size <= max_min_size, + "MIN_SIZE too large. Must be less or equal to {:?}", + max_min_size + ); + + let max_reinsertion_count = max_size - min_size; + assert!( + reinsertion_count < max_reinsertion_count, + "REINSERTION_COUNT too large. Must be smaller than {:?}", + max_reinsertion_count + ); + Params { min_size, max_size, @@ -65,33 +82,4 @@ impl Params { pub fn reinsertion_count(&self) -> usize { self.reinsertion_count } - - /// hi - pub fn check(&self) { - assert!( - self.max_size() >= 4, - "MAX_SIZE too small. Must be larger than 4." - ); - - assert!(self.min_size() > 0, "MIN_SIZE must be at least 1",); - let max_min_size = (self.max_size() + 1) / 2; - assert!( - self.min_size() <= max_min_size, - "MIN_SIZE too large. Must be less or equal to {:?}", - max_min_size - ); - - let max_reinsertion_count = self.max_size() - self.min_size(); - assert!( - self.reinsertion_count() < max_reinsertion_count, - "REINSERTION_COUNT too large. Must be smaller than {:?}", - max_reinsertion_count - ); - - let dimension = ::Point::DIMENSIONS; - assert!( - dimension > 1, - "Point dimension too small - must be at least 2" - ); - } } diff --git a/rstar/src/rtree.rs b/rstar/src/rtree.rs index 2427c95..58ef41f 100644 --- a/rstar/src/rtree.rs +++ b/rstar/src/rtree.rs @@ -208,6 +208,21 @@ where } } +struct PointDimensionAssert { + // See https://github.com/rust-lang/rust/issues/57775#issuecomment-1098001375 + marker: core::marker::PhantomData, +} + +impl PointDimensionAssert +where + T: RTreeObject, +{ + const DIMENSIONS_GOOD: () = assert!( + ::Point::DIMENSIONS > 1, + "Point dimension too small - must be at least 2" + ); +} + impl RTree where T: RTreeObject, @@ -217,9 +232,11 @@ where /// The tree's compile time parameters must be specified. Refer to the /// [RTreeParams] trait for more information and a usage example. pub fn new_with_params(params: Params) -> Self { - params.check::(); + // This is a load-bearing do-nothing statement! + let _ = PointDimensionAssert::::DIMENSIONS_GOOD; + RTree { - root: ParentNode::new_root(¶ms), + root: ParentNode::new_root(params), size: 0, params, } @@ -441,14 +458,16 @@ where fn new_from_bulk_loading( params: Params, elements: Vec, - root_loader: impl Fn(&Params, Vec) -> ParentNode, + root_loader: impl Fn(Params, Vec) -> ParentNode, ) -> Self { - params.check::(); + // This is a load-bearing do-nothing statement! + let _ = PointDimensionAssert::::DIMENSIONS_GOOD; + let size = elements.len(); let root = if size == 0 { - ParentNode::new_root(¶ms) + ParentNode::new_root(params) } else { - root_loader(¶ms, elements) + root_loader(params, elements) }; RTree { root, size, params } } From 99ddffa6235aa972633f8135f79c5a21b03626f2 Mon Sep 17 00:00:00 2001 From: Michael Salib Date: Mon, 14 Nov 2022 07:50:49 -0500 Subject: [PATCH 3/4] whee --- rstar-demo/src/main.rs | 24 ++++++++++-------------- rstar/src/params.rs | 5 ++++- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/rstar-demo/src/main.rs b/rstar-demo/src/main.rs index 0726677..28ea5ea 100644 --- a/rstar-demo/src/main.rs +++ b/rstar-demo/src/main.rs @@ -7,7 +7,7 @@ use kiss3d::window::Window; use nalgebra::{Point2, Point3, Vector2}; use rand::distributions::Uniform; use rand::Rng; -use rstar::{Point, RStarInsertionStrategy, RTree, RTreeNode, RTreeParams, AABB}; +use rstar::{Params, Point, RTree, RTreeNode, AABB}; mod three_d; mod two_d; @@ -67,14 +67,14 @@ impl Scene { fn reset_to_empty(&mut self) { match self.render_mode { - RenderMode::TwoD => self.tree_2d = Default::default(), - RenderMode::ThreeD => self.tree_3d = Default::default(), + RenderMode::TwoD => self.tree_2d = DemoTree2D::new_with_params(params()), + RenderMode::ThreeD => self.tree_3d = DemoTree3D::new_with_params(params()), } } fn bulk_load_tree_3d() -> DemoTree3D { let points_3d = create_random_points(500); - DemoTree3D::bulk_load_with_params(points_3d) + DemoTree3D::bulk_load_with_params(params(), points_3d) } fn bulk_load_tree_2d(window_width: u32, window_height: u32) -> DemoTree2D { @@ -83,24 +83,20 @@ impl Scene { *x = *x * window_width as f32 * 0.5; *y = *y * window_height as f32 * 0.5; } - DemoTree2D::bulk_load_with_params(points_2d) + DemoTree2D::bulk_load_with_params(params(), points_2d) } } -type DemoTree3D = RTree; +fn params() -> Params { + Params::new(5, 9, 3) +} + +type DemoTree3D = RTree; type TreePointType3D = [f32; 3]; type DemoTree2D = RTree; type TreePointType2D = [f32; 2]; -pub struct Params; -impl RTreeParams for Params { - const MIN_SIZE: usize = 5; - const MAX_SIZE: usize = 9; - const REINSERTION_COUNT: usize = 3; - type DefaultInsertionStrategy = RStarInsertionStrategy; -} - pub enum RenderData { ThreeD( Vec, diff --git a/rstar/src/params.rs b/rstar/src/params.rs index ba1bbb1..5aeee71 100644 --- a/rstar/src/params.rs +++ b/rstar/src/params.rs @@ -41,9 +41,12 @@ impl Default for Params { impl Params { /// hi - pub fn new(min_size: usize, max_size: usize, reinsertion_count: usize) -> Self { + pub const fn new(min_size: usize, max_size: usize, reinsertion_count: usize) -> Self { // FIXME: add an Error enum and make this function return // Result instead of asserting.... + + // If we don't want to do that, to make this const, we could + // use the `const_format` crate.... assert!(max_size >= 4, "MAX_SIZE too small. Must be larger than 4."); assert!(min_size > 0, "MIN_SIZE must be at least 1",); From c8d3a649562a128f02c86ed5422fe3fe41ec1525 Mon Sep 17 00:00:00 2001 From: Michael Salib Date: Mon, 14 Nov 2022 07:51:05 -0500 Subject: [PATCH 4/4] sigh --- rstar/src/params.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rstar/src/params.rs b/rstar/src/params.rs index 5aeee71..98fff36 100644 --- a/rstar/src/params.rs +++ b/rstar/src/params.rs @@ -41,7 +41,7 @@ impl Default for Params { impl Params { /// hi - pub const fn new(min_size: usize, max_size: usize, reinsertion_count: usize) -> Self { + pub fn new(min_size: usize, max_size: usize, reinsertion_count: usize) -> Self { // FIXME: add an Error enum and make this function return // Result instead of asserting....