From 606d415d6c66952048477a1c714feace8840df8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Mockers?= Date: Fri, 27 Mar 2026 03:45:45 +0100 Subject: [PATCH 1/7] use rstar instead of bvh2d --- Cargo.toml | 4 ++-- src/layers.rs | 47 +++++++++++++++++++++++------------------------ src/lib.rs | 14 +++++++++----- 3 files changed, 34 insertions(+), 31 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ace2d46..6a4a7ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ verbose = [] async = [] no-default-baking = [] detailed-layers = [] -serde = ["glam/serde", "bvh2d/serde", "dep:serde", "rerecast/serialize"] +serde = ["glam/serde", "rstar/serde", "dep:serde", "rerecast/serialize"] recast = [] [dependencies] @@ -27,7 +27,7 @@ tracing = { version = "0.1", optional = true } hashbrown = { version = "0.16" } glam = { version = "0.30.8", features = ["approx"] } smallvec = { version = "1.15", features = ["union", "const_generics"] } -bvh2d = { version = "0.7" } +rstar = { version = "0.12" } serde = { version = "1.0", features = ["derive"], optional = true } geo = "0.32.0" log = "0.4" diff --git a/src/layers.rs b/src/layers.rs index 1effec6..8b934b3 100644 --- a/src/layers.rs +++ b/src/layers.rs @@ -1,8 +1,8 @@ #[cfg(feature = "tracing")] use tracing::instrument; -use bvh2d::bvh2d::BVH2d; use glam::{vec2, Vec2}; +use rstar::RTree; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -23,7 +23,7 @@ pub struct Layer { #[cfg(feature = "detailed-layers")] #[cfg_attr(docsrs, doc(cfg(feature = "detailed-layers")))] pub scale: Vec2, - pub(crate) baked_polygons: Option, + pub(crate) baked_polygons: Option>, pub(crate) islands: Option>, /// Height of each vertex. Must either have zero elements to ignore heights, or the same length as vertices. pub height: Vec, @@ -110,32 +110,30 @@ impl Layer { pub fn bake_polygon_finder(&mut self) { let bounded_polygons = self .polygons - .iter_mut() - .map(|polygon| BoundedPolygon { - aabb: polygon.vertices.iter().fold( - (vec2(f32::MAX, f32::MAX), Vec2::ZERO), + .iter() + .enumerate() + .map(|(index, polygon)| { + let (min, max) = polygon.vertices.iter().fold( + (vec2(f32::MAX, f32::MAX), vec2(f32::MIN, f32::MIN)), |mut aabb, v| { if let Some(v) = self.vertices.get(*v as usize) { - if v.coords.x < aabb.0.x { - aabb.0.x = v.coords.x; - } - if v.coords.y < aabb.0.y { - aabb.0.y = v.coords.y; - } - if v.coords.x > aabb.1.x { - aabb.1.x = v.coords.x; - } - if v.coords.y > aabb.1.y { - aabb.1.y = v.coords.y; - } + aabb.0.x = aabb.0.x.min(v.coords.x); + aabb.0.y = aabb.0.y.min(v.coords.y); + aabb.1.x = aabb.1.x.max(v.coords.x); + aabb.1.y = aabb.1.y.max(v.coords.y); } aabb }, - ), + ); + BoundedPolygon { + index, + aabb_min: [min.x, min.y], + aabb_max: [max.x, max.y], + } }) .collect::>(); - self.baked_polygons = Some(BVH2d::build(&bounded_polygons)); + self.baked_polygons = Some(RTree::bulk_load(bounded_polygons)); } /// Create a `Layer` from a list of [`Vertex`] and [`Polygon`]. @@ -178,13 +176,14 @@ impl Layer { &'a self, point: &'a Vec2, ) -> impl Iterator + use<'a> { + let query_point = [point.x, point.y]; self.baked_polygons .as_ref() .unwrap() - .contains_iterator(point) - .filter_map(|index| { - self.point_in_polygon(*point, &self.polygons[index]) - .then_some(index as u32) + .locate_in_envelope_intersecting(&rstar::AABB::from_point(query_point)) + .filter_map(|bp| { + self.point_in_polygon(*point, &self.polygons[bp.index]) + .then_some(bp.index as u32) }) } diff --git a/src/lib.rs b/src/lib.rs index 63b1dfd..ec15546 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,6 @@ use std::{ fmt::{self, Debug, Display}, }; -use bvh2d::aabb::{Bounded, AABB}; use glam::{FloatExt, Vec2, Vec3, Vec3Swizzles}; use helpers::{line_intersect_segment, Vec2Helper, EPSILON}; @@ -316,13 +315,18 @@ impl Mesh { } } +#[derive(Debug, Clone)] struct BoundedPolygon { - aabb: (Vec2, Vec2), + index: usize, + aabb_min: [f32; 2], + aabb_max: [f32; 2], } -impl Bounded for BoundedPolygon { - fn aabb(&self) -> AABB { - AABB::with_bounds(self.aabb.0, self.aabb.1) +impl rstar::RTreeObject for BoundedPolygon { + type Envelope = rstar::AABB<[f32; 2]>; + + fn envelope(&self) -> Self::Envelope { + rstar::AABB::from_corners(self.aabb_min, self.aabb_max) } } From 817b43969e959010ccf7487f26f47b4a8bafdee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Mockers?= Date: Fri, 27 Mar 2026 04:05:00 +0100 Subject: [PATCH 2/7] try rstar improvement --- Cargo.toml | 2 +- src/lib.rs | 2 +- thirdparty/rstar/.cargo-checksum.json | 1 + thirdparty/rstar/.cargo_vcs_info.json | 6 + thirdparty/rstar/CHANGELOG.md | 126 ++ thirdparty/rstar/Cargo.toml | 93 ++ thirdparty/rstar/Cargo.toml.orig | 34 + thirdparty/rstar/README.md | 77 ++ thirdparty/rstar/src/aabb.rs | 280 ++++ .../bulk_load/bulk_load_sequential.rs | 149 +++ .../bulk_load/cluster_group_iterator.rs | 99 ++ .../rstar/src/algorithm/bulk_load/mod.rs | 4 + .../src/algorithm/intersection_iterator.rs | 156 +++ thirdparty/rstar/src/algorithm/iterators.rs | 419 ++++++ thirdparty/rstar/src/algorithm/mod.rs | 8 + .../rstar/src/algorithm/nearest_neighbor.rs | 405 ++++++ thirdparty/rstar/src/algorithm/removal.rs | 397 ++++++ thirdparty/rstar/src/algorithm/rstar.rs | 354 +++++ .../src/algorithm/selection_functions.rs | 241 ++++ thirdparty/rstar/src/envelope.rs | 72 + thirdparty/rstar/src/lib.rs | 64 + thirdparty/rstar/src/mint.rs | 94 ++ thirdparty/rstar/src/node.rs | 168 +++ thirdparty/rstar/src/object.rs | 233 ++++ thirdparty/rstar/src/params.rs | 116 ++ thirdparty/rstar/src/point.rs | 437 ++++++ .../rstar/src/primitives/cached_envelope.rs | 127 ++ .../rstar/src/primitives/geom_with_data.rs | 136 ++ thirdparty/rstar/src/primitives/line.rs | 142 ++ thirdparty/rstar/src/primitives/mod.rs | 15 + thirdparty/rstar/src/primitives/object_ref.rs | 62 + .../rstar/src/primitives/point_with_data.rs | 72 + thirdparty/rstar/src/primitives/rectangle.rs | 134 ++ thirdparty/rstar/src/rtree.rs | 1167 +++++++++++++++++ thirdparty/rstar/src/test_utilities.rs | 51 + 35 files changed, 5941 insertions(+), 2 deletions(-) create mode 100644 thirdparty/rstar/.cargo-checksum.json create mode 100644 thirdparty/rstar/.cargo_vcs_info.json create mode 100644 thirdparty/rstar/CHANGELOG.md create mode 100644 thirdparty/rstar/Cargo.toml create mode 100644 thirdparty/rstar/Cargo.toml.orig create mode 100644 thirdparty/rstar/README.md create mode 100644 thirdparty/rstar/src/aabb.rs create mode 100644 thirdparty/rstar/src/algorithm/bulk_load/bulk_load_sequential.rs create mode 100644 thirdparty/rstar/src/algorithm/bulk_load/cluster_group_iterator.rs create mode 100644 thirdparty/rstar/src/algorithm/bulk_load/mod.rs create mode 100644 thirdparty/rstar/src/algorithm/intersection_iterator.rs create mode 100644 thirdparty/rstar/src/algorithm/iterators.rs create mode 100644 thirdparty/rstar/src/algorithm/mod.rs create mode 100644 thirdparty/rstar/src/algorithm/nearest_neighbor.rs create mode 100644 thirdparty/rstar/src/algorithm/removal.rs create mode 100644 thirdparty/rstar/src/algorithm/rstar.rs create mode 100644 thirdparty/rstar/src/algorithm/selection_functions.rs create mode 100644 thirdparty/rstar/src/envelope.rs create mode 100644 thirdparty/rstar/src/lib.rs create mode 100644 thirdparty/rstar/src/mint.rs create mode 100644 thirdparty/rstar/src/node.rs create mode 100644 thirdparty/rstar/src/object.rs create mode 100644 thirdparty/rstar/src/params.rs create mode 100644 thirdparty/rstar/src/point.rs create mode 100644 thirdparty/rstar/src/primitives/cached_envelope.rs create mode 100644 thirdparty/rstar/src/primitives/geom_with_data.rs create mode 100644 thirdparty/rstar/src/primitives/line.rs create mode 100644 thirdparty/rstar/src/primitives/mod.rs create mode 100644 thirdparty/rstar/src/primitives/object_ref.rs create mode 100644 thirdparty/rstar/src/primitives/point_with_data.rs create mode 100644 thirdparty/rstar/src/primitives/rectangle.rs create mode 100644 thirdparty/rstar/src/rtree.rs create mode 100644 thirdparty/rstar/src/test_utilities.rs diff --git a/Cargo.toml b/Cargo.toml index 6a4a7ce..0f8e5b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ tracing = { version = "0.1", optional = true } hashbrown = { version = "0.16" } glam = { version = "0.30.8", features = ["approx"] } smallvec = { version = "1.15", features = ["union", "const_generics"] } -rstar = { version = "0.12" } +rstar = { version = "0.12", path = "thirdparty/rstar" } serde = { version = "1.0", features = ["derive"], optional = true } geo = "0.32.0" log = "0.4" diff --git a/src/lib.rs b/src/lib.rs index ec15546..5a98758 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -326,7 +326,7 @@ impl rstar::RTreeObject for BoundedPolygon { type Envelope = rstar::AABB<[f32; 2]>; fn envelope(&self) -> Self::Envelope { - rstar::AABB::from_corners(self.aabb_min, self.aabb_max) + rstar::AABB::from_sorted(self.aabb_min, self.aabb_max) } } diff --git a/thirdparty/rstar/.cargo-checksum.json b/thirdparty/rstar/.cargo-checksum.json new file mode 100644 index 0000000..a25b60d --- /dev/null +++ b/thirdparty/rstar/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"c5544a43d973aa7f53ae32efe80a36cc68ebb6a3c512afc9324a61b6c9b41044","CHANGELOG.md":"5424e21bcea1be22cecd68185e83288cd43f9ce28a2115d394225ec4da0f2d0b","Cargo.toml":"025bb74e428ccebfe3598b18318ec1183720521810250b83e9895e13484c591f","Cargo.toml.orig":"5fcc9507370e3cc11bb34406c7469b39662cb4a851d7cb098bacac234692cc53","README.md":"35badde6b30495407f9ac995fbac367ed454edbdc5fa1b0151dd05dd77347f3b","src/aabb.rs":"5f2ebfaa9f6af57c09db519debe0b133972078df1cd43e6677fefecbb822e4b1","src/algorithm/bulk_load/bulk_load_sequential.rs":"101f7fe86b01d82373bff72d9528a02cfa0215c21f63a1c894709bb7e7bf168a","src/algorithm/bulk_load/cluster_group_iterator.rs":"0518678a4d5a1a2bb1f9deecc677904f6890f67abcb2ca8ce10f3a13e1a56719","src/algorithm/bulk_load/mod.rs":"f6f3f015ea2d6c8b0342616bb993f6be35f40836795daabac6b2eb2d354e57b3","src/algorithm/intersection_iterator.rs":"9b939ad49d9c678c1af2d54058638158f0d5c0faa1baff2e3ed3b67b7104a581","src/algorithm/iterators.rs":"0d830b691ba7265028ae7b4251d04dc59192a43ddb62da17e58eae6abd4aa13e","src/algorithm/mod.rs":"4085dd753a5f7c779a80dcad72098f26aa3ba6701292a766572b605c4e86a192","src/algorithm/nearest_neighbor.rs":"d4a3b147c21b69da2373f33f4ebb4d0d11322649122c46708a7937aab68e2138","src/algorithm/removal.rs":"174cb3d9d8b965f07b537408e6bc82833dd303ab6ff3a10c325f0773ea46b10d","src/algorithm/rstar.rs":"1bdb4218da229627181aa469627819018f88e6c6efe8ab1fadb520a2dbf83e40","src/algorithm/selection_functions.rs":"6ce0395ae821e09ed1d4325f43fec48b47b56ae3b861e1aa02769cb669a275f9","src/envelope.rs":"9b8800ce33701f14331e791c04f8a9192856e514ea2fd6f8c5890dbca682fa4b","src/lib.rs":"50d187e5b3e0edb373a31a74bbe7a4fe0072b2541d684ecf7fb7a247020cf4ff","src/mint.rs":"522ca5e07b5510b73bb60a70d8022e7ff48a7ed6f94ac797034aeb81e6760266","src/node.rs":"b5577b72072c0ef4776665de84007a177f7a249ad055964a691baa7d81350d34","src/object.rs":"dfd93bca931fdb61bb0fd0e320552843a3f79d6829e70423e47053015b18b81c","src/params.rs":"4f45e7dc147e0fccb46ed7c8b7c6ef0edbba682ea68c01ce53270cbd81722a4e","src/point.rs":"4908f76d30fa5ae5049a0bbbf26c116e9a8cacc86104ff1bd9b93eca23003d52","src/primitives/cached_envelope.rs":"7524b6261b20bd06e7f670427f61d3c4cbdb7640fe7cff3af4f6f0aa29955569","src/primitives/geom_with_data.rs":"fa5a715a579a09dfc85d2cf7a9d54abb0e01e91f9caee30085d1a3cb82721ed6","src/primitives/line.rs":"59b19c6ee0e3d2da172b43150da68a328b44521f1efe5bedd3ce13d5cd2830c7","src/primitives/mod.rs":"0dff8cd779cc848fd0d993e6a3427cb0fa2a8789bf51814b12a73fdba461f7b9","src/primitives/object_ref.rs":"2c979f2189c21e0310a47e3445ad7a62f1fbf5e042b3f8b06ac511ae41c9fd7a","src/primitives/point_with_data.rs":"8bfd88c5e1a2a466ecc61cc57a3458009cb65f5716547fec83c94fb1f952bb64","src/primitives/rectangle.rs":"fe49dc601a05ea9d339927854977f302955a403c898277fda5b28bdeeeda49f5","src/rtree.rs":"6c2441fc60d411ef07dfb82695173d28742bbfb82962aeca170fc7f0b39c7ff3","src/test_utilities.rs":"28ce88bf0b533332aa53fff49431fbf8e644acac6f30fe657b50b02da76322d9"},"package":"421400d13ccfd26dfa5858199c30a5d76f9c54e0dba7575273025b43c5175dbb"} \ No newline at end of file diff --git a/thirdparty/rstar/.cargo_vcs_info.json b/thirdparty/rstar/.cargo_vcs_info.json new file mode 100644 index 0000000..d62ce33 --- /dev/null +++ b/thirdparty/rstar/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "c8c5bf9e41468281d030869d409e3f67f1aaf5b7" + }, + "path_in_vcs": "rstar" +} \ No newline at end of file diff --git a/thirdparty/rstar/CHANGELOG.md b/thirdparty/rstar/CHANGELOG.md new file mode 100644 index 0000000..27ea20a --- /dev/null +++ b/thirdparty/rstar/CHANGELOG.md @@ -0,0 +1,126 @@ +# 0.12.2 + +## Changed +- Reverted the change to `AABB::new_empty` while still avoiding overflow panics applying selections on empty trees ([PR](https://github.com/georust/rstar/pull/184) + +# 0.12.1 **YANKED** + +## Added +- Provide selection methods based on internal iteration ([PR](https://github.com/georust/rstar/pull/164)) +- Add ObjectRef combinator to build tree referencing objects elsewhere ([PR](https://github.com/georust/rstar/pull/178)) + +## Changed +- Switched to unstable sort for envelopes and node reinsertion ([PR](https://github.com/georust/rstar/pull/160)) +- Use a more tame value for `AABB::new_empty` to avoid overflow panics applying selections on empty trees ([PR](https://github.com/georust/rstar/pull/162)) +- Avoid infinite recursion due to numerical instability when computing the number of clusters ([PR](https://github.com/georust/rstar/pull/166)) + + +# 0.12.0 + +## Added +- Add optional support for the [mint](https://docs.rs/mint/0.5.9/mint/index.html) crate +- Implemented `IntoIter` for `RTree`, i.e. added a owning iterator +- Added cached envelope bulk load benchmark +- Implemented `Hash` for `AABB`, `Line`, and `Rectangle`, provided the `Point` used implements `Hash` itself +- Implemented `Default` for `DefaultParams` + +## Changed +- Fixed a stack overflow error in `DrainIterator::next` +- Clarified that the distance measure in `distance_2` is not restricted to euclidean distance +- updated to `heapless=0.8` +- Updated CI config to use merge queue ([PR](https://github.com/georust/rstar/pull/143)) + +# 0.11.0 + +## Added +- Add `CachedEnvelope` combinator which simplifies memoizing envelope computations. ([PR](https://github.com/georust/rstar/pull/118)) +- `Point` is now implemented as const generic for any length of `RTreeNum` array + +## Changed +- Increase our MSRV to Rust 1.63 following that of the `geo` crate. ([PR](https://github.com/georust/rstar/pull/124)) + +# 0.10.0 + +## Added +- Added method `RTree::drain()`. +- Changed license field to [SPDX 2.1 license expression](https://spdx.dev/spdx-specification-21-web-version/#h.jxpfx0ykyb60) + +## Changed +- fixed all clippy lint issues +- Fixed error when setting MIN_SIZE = 1 in `RTreeParams` and added assert for positive MIN_SIZE +- BREAKING: Removed the `Copy` bound from `Point` and `Envelope`. ([PR](https://github.com/georust/rstar/pull/103)) + +# 0.9.3 +## Changed +- Removed dependency on `pdqselect` ([PR](https://github.com/georust/rstar/pull/85)) +- New **minimal supported rust version (MSRV): 1.51.0** +- Replace all usages of `std` with `core` & `alloc` to make `rstar` fit for + `no_std`. ([PR](https://github.com/georust/rstar/pull/83)) +- Updated `heapless` dependency to 0.7 to make use of const generics. ([PR](https://github.com/georust/rstar/pull/87)) + + +# 0.9.2 +- Add `RTree::drain_*` methods to remove and drain selected items. ([PR](https://github.com/georust/rstar/pull/77)) +- Add trait `Point` for tuples containing elements of the same type, up to nine dimensions. +- Pinned `pdqselect` to 0.1.0 as 0.1.1 has switched to the 2021 edition + +## Changed +- Expose all iterator types in `crate::iterators` module ([PR](https://github.com/georust/rstar/pull/77)) + +# 0.9.1 + +## Added +- A generic container for a geometry and associated data: `GeomWithData` ([PR](https://github.com/georust/rstar/pull/74)) + +# 0.9.0 + +## Added +- `RTree::nearest_neighbors` method based on + [spade crate's implementation](https://github.com/Stoeoef/spade) + +## Changed +- Fix floating point inconsistency in `min_max_dist_2` ([PR](https://github.com/georust/rstar/pull/40)). +- BREAKING: `Point::generate` function now accepts a `impl FnMut`. Custom implementations of `Point` must change to + accept `impl FnMut` instead of `impl Fn`. Callers of `Point::generate` should not require changes. +- Update CI images to Stable Rust 1.50 and 1.51 +- Run clippy, rustfmt, update manifest to reflect ownership changes +- Update Criterion and rewrite deprecated benchmark functions +- Remove unused imports +- Remove executable bit from files +- Fix typos, modernize links + +# 0.8.3 +## Changed +- Move crate ownership to the georust organization +## Fixed +- Update dependencies to remove heapless 0.5, which has a known vulnerability + +# 0.8.2 - 2020-08-01 +## Fixed: + - Fixed a rare panic when calling `insert` (See #45) + +# 0.8.1 - 2020-06-18 +## Changed: + + - Fine tuned nearest neighbor iterator inline capacity (see #39). This should boost performance in some cases. + +# 0.8.0 - 2020-05-25 +## Fixed: + + - Bugfix: `RTree::locate_with_selection_function_mut` sometimes returned too many elements for small trees. +## Changed: + - Deprecated `RTree::nearest_neighbor_iter_with_distance`. The name is misleading, use `RTree::nearest_neighbor_iter_with_distance_2` instead. + - Some performance improvements, see #38 and #35 + +## Added + - Added `nearest_neighbor_iter_with_distance_2` #31 + +# 0.7.1 - 2020-01-16 +## Changed: + - `RTree::intersection_candidates_with_other_tree` can now calculate intersections of trees of different item types (see #23) + +# 0.7.0 - 2019-11-25 +## Added: + - `RTree::remove_with_selection_function` + - `RTree::pop_nearest_neighbor` + - Added CHANGELOG.md diff --git a/thirdparty/rstar/Cargo.toml b/thirdparty/rstar/Cargo.toml new file mode 100644 index 0000000..42a2678 --- /dev/null +++ b/thirdparty/rstar/Cargo.toml @@ -0,0 +1,93 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +rust-version = "1.63" +name = "rstar" +version = "0.12.2" +authors = [ + "Stefan Altmayer ", + "The Georust Developers ", +] +build = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "An R*-tree spatial index" +documentation = "https://docs.rs/rstar/" +readme = "README.md" +keywords = [ + "rtree", + "r-tree", + "spatial", + "spatial-index", + "nearest-neighbor", +] +categories = [ + "data-structures", + "algorithms", + "science::geo", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/georust/rstar" + +[lib] +name = "rstar" +path = "src/lib.rs" + +[dependencies.heapless] +version = "0.8" + +[dependencies.mint] +version = "0.5.9" +optional = true + +[dependencies.num-traits] +version = "0.2" +features = ["libm"] +default-features = false + +[dependencies.serde] +version = "1.0" +features = [ + "alloc", + "derive", +] +optional = true +default-features = false + +[dependencies.smallvec] +version = "1.6" + +[dev-dependencies.approx] +version = "0.3" + +[dev-dependencies.nalgebra] +version = "0.32.3" +features = ["mint"] + +[dev-dependencies.rand] +version = "0.7" + +[dev-dependencies.rand_hc] +version = "0.2" + +[dev-dependencies.serde_json] +version = "1.0" + +[features] +debug = [] +default = [] + +[badges.maintenance] +status = "actively-developed" diff --git a/thirdparty/rstar/Cargo.toml.orig b/thirdparty/rstar/Cargo.toml.orig new file mode 100644 index 0000000..b8ae9ca --- /dev/null +++ b/thirdparty/rstar/Cargo.toml.orig @@ -0,0 +1,34 @@ +[package] +name = "rstar" +version = "0.12.2" +authors = ["Stefan Altmayer ", "The Georust Developers "] +description = "An R*-tree spatial index" +documentation = "https://docs.rs/rstar/" +repository = "https://github.com/georust/rstar" +license = "MIT OR Apache-2.0" +readme = "README.md" +edition = "2018" +rust-version = "1.63" +keywords = ["rtree", "r-tree", "spatial", "spatial-index", "nearest-neighbor"] +categories = ["data-structures", "algorithms", "science::geo"] + +[badges] +maintenance = { status = "actively-developed" } + +[dependencies] +heapless = "0.8" +num-traits = { version = "0.2", default-features = false, features = ["libm"] } +serde = { version = "1.0", optional = true, default-features = false, features = ["alloc", "derive"] } +smallvec = "1.6" +mint = { version = "0.5.9", optional = true } + +[features] +default = [] +debug = [] + +[dev-dependencies] +rand = "0.7" +rand_hc = "0.2" +approx = "0.3" +serde_json = "1.0" +nalgebra = { version = "0.32.3", features = ["mint"] } diff --git a/thirdparty/rstar/README.md b/thirdparty/rstar/README.md new file mode 100644 index 0000000..763385d --- /dev/null +++ b/thirdparty/rstar/README.md @@ -0,0 +1,77 @@ +# rstar + +A flexible, n-dimensional [r*-tree](https://en.wikipedia.org/wiki/R*_tree) implementation for the Rust ecosystem, suitable for use as a spatial index. + +# Features + - A flexible r*-tree written in safe rust + - Supports custom point types + - Supports the insertion of user defined types + - Supported operations: + - Insertion + - Rectangle queries + - Nearest neighbor + - Nearest neighbor iteration + - Locate at point + - Element removal + - Efficient bulk loading + - Features geometric primitives that can readily be inserted into an r-tree: + - Points (arrays with a constant size) + - Lines + - Rectangles + - Small number of dependencies + - Serde support with the `serde` feature + - `no_std` compatible (but requires [`alloc`](https://doc.rust-lang.org/alloc/)) + +## Geometries + +Primitives are provided for point, line, and rectangle geometries. The [`geo`](https://crates.io/crates/geo) crate uses rstar as an efficient spatial index and provides [`RTreeObject`](file:///Users/sth/dev/rstar/target/doc/rstar/trait.RTreeObject.html) implementations for storing complex geometries such as linestrings and polygons. + +# Benchmarks +All benchmarks are performed on a i7-8550U CPU @ 1.80Ghz and with uniformly distributed points. The underlying point type is `[f64; 2]`. + +| Benchmark | Tree size | Time | +|-------------------------------------|-----:|----------:| +| bulk loading | 2000 | 229.82 us | +| sequentially loading | 2000 | 1.4477 ms | +| nearest neighbor (bulk loaded tree) | 100k | 1.32 us | +| nearest neighbor (sequential tree) | 100k | 1.56 us | +| successful point lookup | 100k | 177.32 ns | +| unsuccessful point lookup | 100k | 273.51 ns | + +# Project state +The project is being actively developed, feature requests and PRs are welcome! + +# Documentation +The documentation is hosted on [docs.rs](https://docs.rs/rstar/). + +# Release Checklist + +The crate can be published by the `rstar-publishers` team of +georust. Please follow the steps below while publishing a +new release. + +1. Create branch from master, say `release/`. +2. Ensure `rstar/CHANGELOG.md` describes all the changes + since last release (esp. the breaking ones). +3. Ensure / set `version` metadata in `Cargo.toml` of + `rstar` to the new version. +4. Create PR to master, have it approved and merge. +5. Checkout the updated master, go to `rstar` directory and + run `cargo publish`. +6. Create tag `` and push to `georust/rstar` + +# License + +Licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +## Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. diff --git a/thirdparty/rstar/src/aabb.rs b/thirdparty/rstar/src/aabb.rs new file mode 100644 index 0000000..5bfcf6a --- /dev/null +++ b/thirdparty/rstar/src/aabb.rs @@ -0,0 +1,280 @@ +use crate::point::{max_inline, Point, PointExt}; +use crate::{Envelope, RTreeObject}; +use num_traits::{Bounded, One, Zero}; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +/// An n-dimensional axis aligned bounding box (AABB). +/// +/// An object's AABB is the smallest box totally encompassing an object +/// while being aligned to the current coordinate system. +/// Although these structures are commonly called bounding _boxes_, they exist in any +/// dimension. +/// +/// Note that AABBs cannot be inserted into r-trees. Use the +/// [Rectangle](crate::primitives::Rectangle) struct for this purpose. +/// +/// # Type arguments +/// `P`: The struct is generic over which point type is used. Using an n-dimensional point +/// type will result in an n-dimensional bounding box. +#[derive(Clone, Debug, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct AABB

+where + P: Point, +{ + lower: P, + upper: P, +} + +impl

AABB

+where + P: Point, +{ + /// Returns the AABB encompassing a single point. + pub fn from_point(p: P) -> Self { + AABB { + lower: p.clone(), + upper: p, + } + } + + /// Returns the AABB's lower corner. + /// + /// This is the point contained within the AABB with the smallest coordinate value in each + /// dimension. + pub fn lower(&self) -> P { + self.lower.clone() + } + + /// Returns the AABB's upper corner. + /// + /// This is the point contained within the AABB with the largest coordinate value in each + /// dimension. + pub fn upper(&self) -> P { + self.upper.clone() + } + + /// Creates a new AABB encompassing two points. + pub fn from_corners(p1: P, p2: P) -> Self { + AABB { + lower: p1.min_point(&p2), + upper: p1.max_point(&p2), + } + } + + /// Creates a new AABB from pre-sorted lower and upper bounds. + /// + /// The caller must ensure that `lower` component-wise <= `upper`. + /// No min/max computation is performed. + pub fn from_sorted(lower: P, upper: P) -> Self { + AABB { lower, upper } + } + + /// Creates a new AABB encompassing a collection of points. + pub fn from_points<'a, I>(i: I) -> Self + where + I: IntoIterator + 'a, + P: 'a, + { + i.into_iter().fold( + Self { + lower: P::from_value(P::Scalar::max_value()), + upper: P::from_value(P::Scalar::min_value()), + }, + |aabb, p| Self { + lower: aabb.lower.min_point(p), + upper: aabb.upper.max_point(p), + }, + ) + } + + /// Returns the point within this AABB closest to a given point. + /// + /// If `point` is contained within the AABB, `point` will be returned. + pub fn min_point(&self, point: &P) -> P { + self.upper.min_point(&self.lower.max_point(point)) + } + + /// Returns the squared distance to the AABB's [min_point](AABB::min_point) + pub fn distance_2(&self, point: &P) -> P::Scalar { + if self.contains_point(point) { + Zero::zero() + } else { + self.min_point(point).sub(point).length_2() + } + } +} + +impl

Envelope for AABB

+where + P: Point, +{ + type Point = P; + + fn new_empty() -> Self { + let max = P::Scalar::max_value(); + let min = P::Scalar::min_value(); + Self { + lower: P::from_value(max), + upper: P::from_value(min), + } + } + + fn contains_point(&self, point: &P) -> bool { + self.lower.all_component_wise(point, |x, y| x <= y) + && self.upper.all_component_wise(point, |x, y| x >= y) + } + + fn contains_envelope(&self, other: &Self) -> bool { + self.lower.all_component_wise(&other.lower, |l, r| l <= r) + && self.upper.all_component_wise(&other.upper, |l, r| l >= r) + } + + fn merge(&mut self, other: &Self) { + self.lower = self.lower.min_point(&other.lower); + self.upper = self.upper.max_point(&other.upper); + } + + fn merged(&self, other: &Self) -> Self { + AABB { + lower: self.lower.min_point(&other.lower), + upper: self.upper.max_point(&other.upper), + } + } + + fn intersects(&self, other: &Self) -> bool { + self.lower.all_component_wise(&other.upper, |l, r| l <= r) + && self.upper.all_component_wise(&other.lower, |l, r| l >= r) + } + + fn area(&self) -> P::Scalar { + let zero = P::Scalar::zero(); + let one = P::Scalar::one(); + let diag = self.upper.sub(&self.lower); + diag.fold(one, |acc, cur| max_inline(cur, zero) * acc) + } + + fn distance_2(&self, point: &P) -> P::Scalar { + self.distance_2(point) + } + + fn min_max_dist_2(&self, point: &P) ->

::Scalar { + let l = self.lower.sub(point); + let u = self.upper.sub(point); + let mut max_diff = (Zero::zero(), Zero::zero(), 0); // diff, min, index + let mut result = P::new(); + + for i in 0..P::DIMENSIONS { + let mut min = l.nth(i); + let mut max = u.nth(i); + max = max * max; + min = min * min; + if max < min { + core::mem::swap(&mut min, &mut max); + } + + let diff = max - min; + *result.nth_mut(i) = max; + + if diff >= max_diff.0 { + max_diff = (diff, min, i); + } + } + + *result.nth_mut(max_diff.2) = max_diff.1; + result.fold(Zero::zero(), |acc, curr| acc + curr) + } + + fn center(&self) -> Self::Point { + let one = ::Scalar::one(); + let two = one + one; + self.lower.component_wise(&self.upper, |x, y| (x + y) / two) + } + + fn intersection_area(&self, other: &Self) -> ::Scalar { + AABB { + lower: self.lower.max_point(&other.lower), + upper: self.upper.min_point(&other.upper), + } + .area() + } + + fn perimeter_value(&self) -> P::Scalar { + let diag = self.upper.sub(&self.lower); + let zero = P::Scalar::zero(); + max_inline(diag.fold(zero, |acc, value| acc + value), zero) + } + + fn sort_envelopes>(axis: usize, envelopes: &mut [T]) { + envelopes.sort_unstable_by(|l, r| { + l.envelope() + .lower + .nth(axis) + .partial_cmp(&r.envelope().lower.nth(axis)) + .unwrap() + }); + } + + fn partition_envelopes>( + axis: usize, + envelopes: &mut [T], + selection_size: usize, + ) { + envelopes.select_nth_unstable_by(selection_size, |l, r| { + l.envelope() + .lower + .nth(axis) + .partial_cmp(&r.envelope().lower.nth(axis)) + .unwrap() + }); + } +} + +#[cfg(test)] +mod test { + use super::AABB; + use crate::envelope::Envelope; + use crate::object::PointDistance; + + #[test] + fn empty_rect() { + let empty = AABB::<[f32; 2]>::new_empty(); + + let other = AABB::from_corners([1.0, 1.0], [1.0, 1.0]); + let subject = empty.merged(&other); + assert_eq!(other, subject); + + let other = AABB::from_corners([0.0, 0.0], [0.0, 0.0]); + let subject = empty.merged(&other); + assert_eq!(other, subject); + + let other = AABB::from_corners([0.5, 0.5], [0.5, 0.5]); + let subject = empty.merged(&other); + assert_eq!(other, subject); + + let other = AABB::from_corners([-0.5, -0.5], [-0.5, -0.5]); + let subject = empty.merged(&other); + assert_eq!(other, subject); + } + + /// Test that min_max_dist_2 is identical to distance_2 for the equivalent + /// min max corner of the AABB. This is necessary to prevent optimizations + /// from inadvertently changing floating point order of operations. + #[test] + fn test_min_max_dist_2_issue_40_regression() { + let a = [0.7018702292340033, 0.2121617955083932, 0.8120562975177115]; + let b = [0.7297749764202988, 0.23020869735094462, 0.8194675310336391]; + let aabb = AABB::from_corners(a, b); + let p = [0.6950876013070484, 0.220750082121574, 0.8186032137709887]; + let corner = [a[0], b[1], a[2]]; + assert_eq!(aabb.min_max_dist_2(&p), corner.distance_2(&p)); + } + + #[test] + fn test_from_points_issue_170_regression() { + let aabb = AABB::from_points(&[(3., 3., 3.), (4., 4., 4.)]); + assert_eq!(aabb, AABB::from_corners((3., 3., 3.), (4., 4., 4.))); + } +} diff --git a/thirdparty/rstar/src/algorithm/bulk_load/bulk_load_sequential.rs b/thirdparty/rstar/src/algorithm/bulk_load/bulk_load_sequential.rs new file mode 100644 index 0000000..ca75d8a --- /dev/null +++ b/thirdparty/rstar/src/algorithm/bulk_load/bulk_load_sequential.rs @@ -0,0 +1,149 @@ +use crate::envelope::Envelope; +use crate::node::{ParentNode, RTreeNode}; +use crate::object::RTreeObject; +use crate::params::RTreeParams; +use crate::point::Point; + +#[cfg(not(test))] +use alloc::{vec, vec::Vec}; + +#[allow(unused_imports)] // Import is required when building without std +use num_traits::Float; + +use super::cluster_group_iterator::{calculate_number_of_clusters_on_axis, ClusterGroupIterator}; + +fn bulk_load_recursive(elements: Vec) -> ParentNode +where + T: RTreeObject, + ::Point: Point, + Params: RTreeParams, +{ + 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()).max(2); + + let iterator = PartitioningTask::<_, Params> { + number_of_clusters_on_axis, + work_queue: vec![PartitioningState { + current_axis: ::Point::DIMENSIONS, + elements, + }], + _params: Default::default(), + }; + ParentNode::new_parent(iterator.collect()) +} + +/// Represents a partitioning task that still needs to be done. +/// +/// A partitioning iterator will take this item from its work queue and start partitioning "elements" +/// along "current_axis" . +struct PartitioningState { + elements: Vec, + current_axis: usize, +} + +/// Successively partitions the given elements into cluster groups and finally into clusters. +struct PartitioningTask { + work_queue: Vec>, + number_of_clusters_on_axis: usize, + _params: core::marker::PhantomData, +} + +impl Iterator for PartitioningTask { + type Item = RTreeNode; + + fn next(&mut self) -> Option { + while let Some(next) = self.work_queue.pop() { + let PartitioningState { + elements, + current_axis, + } = next; + if current_axis == 0 { + // Partitioning finished successfully on all axis. The remaining cluster forms a new node + let data = bulk_load_recursive::<_, Params>(elements); + return RTreeNode::Parent(data).into(); + } else { + // The cluster group needs to be partitioned further along the next axis + let iterator = ClusterGroupIterator::new( + elements, + self.number_of_clusters_on_axis, + current_axis - 1, + ); + self.work_queue + .extend(iterator.map(|slab| PartitioningState { + elements: slab, + current_axis: current_axis - 1, + })); + } + } + None + } +} + +/// 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(elements: Vec) -> ParentNode +where + T: RTreeObject, + ::Point: Point, + Params: RTreeParams, +{ + bulk_load_recursive::<_, Params>(elements) +} + +#[cfg(test)] +mod test { + use crate::test_utilities::*; + use crate::{Point, RTree, RTreeObject}; + use std::collections::HashSet; + use std::fmt::Debug; + use std::hash::Hash; + + #[test] + fn test_bulk_load_small() { + let random_points = create_random_integers::<[i32; 2]>(50, SEED_1); + create_and_check_bulk_loading_with_points(&random_points); + } + + #[test] + fn test_bulk_load_large() { + let random_points = create_random_integers::<[i32; 2]>(3000, SEED_1); + create_and_check_bulk_loading_with_points(&random_points); + } + + #[test] + fn test_bulk_load_with_different_sizes() { + for size in (0..100).map(|i| i * 7) { + test_bulk_load_with_size_and_dimension::<[i32; 2]>(size); + test_bulk_load_with_size_and_dimension::<[i32; 3]>(size); + test_bulk_load_with_size_and_dimension::<[i32; 4]>(size); + } + } + + fn test_bulk_load_with_size_and_dimension

(size: usize) + where + P: Point + RTreeObject + Send + Sync + Eq + Clone + Debug + Hash + 'static, + P::Envelope: Send + Sync, + { + let random_points = create_random_integers::

(size, SEED_1); + create_and_check_bulk_loading_with_points(&random_points); + } + + fn create_and_check_bulk_loading_with_points

(points: &[P]) + where + P: RTreeObject + Send + Sync + Eq + Clone + Debug + Hash + 'static, + P::Envelope: Send + Sync, + { + let tree = RTree::bulk_load(points.into()); + let set1: HashSet<_> = tree.iter().collect(); + let set2: HashSet<_> = points.iter().collect(); + assert_eq!(set1, set2); + assert_eq!(tree.size(), points.len()); + } +} diff --git a/thirdparty/rstar/src/algorithm/bulk_load/cluster_group_iterator.rs b/thirdparty/rstar/src/algorithm/bulk_load/cluster_group_iterator.rs new file mode 100644 index 0000000..6200442 --- /dev/null +++ b/thirdparty/rstar/src/algorithm/bulk_load/cluster_group_iterator.rs @@ -0,0 +1,99 @@ +use crate::{Envelope, Point, RTreeObject, RTreeParams}; + +#[cfg(not(test))] +use alloc::vec::Vec; + +#[allow(unused_imports)] // Import is required when building without std +use num_traits::Float; + +/// Partitions elements into groups of clusters along a specific axis. +pub struct ClusterGroupIterator { + remaining: Vec, + slab_size: usize, + pub cluster_dimension: usize, +} + +impl ClusterGroupIterator { + pub fn new( + elements: Vec, + number_of_clusters_on_axis: usize, + cluster_dimension: usize, + ) -> Self { + let slab_size = div_up(elements.len(), number_of_clusters_on_axis); + ClusterGroupIterator { + remaining: elements, + slab_size, + cluster_dimension, + } + } +} + +impl Iterator for ClusterGroupIterator { + type Item = Vec; + + fn next(&mut self) -> Option { + match self.remaining.len() { + 0 => None, + len if len <= self.slab_size => ::core::mem::take(&mut self.remaining).into(), + _ => { + let slab_axis = self.cluster_dimension; + T::Envelope::partition_envelopes(slab_axis, &mut self.remaining, self.slab_size); + let off_split = self.remaining.split_off(self.slab_size); + ::core::mem::replace(&mut self.remaining, off_split).into() + } + } + } +} + +/// 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 +where + T: RTreeObject, + Params: RTreeParams, +{ + 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 i32; + // The number of elements each subtree will hold + let n_subtree = max_size.powi(depth - 1); + // How many clusters will this node contain + let number_of_clusters = (number_of_elements as f32 / n_subtree).ceil(); + + let max_dimension = ::Point::DIMENSIONS as f32; + // Try to split all clusters among all dimensions as evenly as possible by taking the nth root. + number_of_clusters.powf(1. / max_dimension).ceil() as usize +} + +fn div_up(dividend: usize, divisor: usize) -> usize { + (dividend + divisor - 1) / divisor +} + +#[cfg(test)] +mod test { + use super::ClusterGroupIterator; + + #[test] + fn test_cluster_group_iterator() { + const SIZE: usize = 374; + const NUMBER_OF_CLUSTERS_ON_AXIS: usize = 5; + let elements: Vec<_> = (0..SIZE as i32).map(|i| [-i, -i]).collect(); + let slab_size = (elements.len()) / NUMBER_OF_CLUSTERS_ON_AXIS + 1; + let slabs: Vec<_> = + ClusterGroupIterator::new(elements, NUMBER_OF_CLUSTERS_ON_AXIS, 0).collect(); + assert_eq!(slabs.len(), NUMBER_OF_CLUSTERS_ON_AXIS); + for slab in &slabs[0..slabs.len() - 1] { + assert_eq!(slab.len(), slab_size); + } + let mut total_size = 0; + let mut max_element_for_last_slab = i32::MIN; + for slab in &slabs { + total_size += slab.len(); + let current_max = slab.iter().max_by_key(|point| point[0]).unwrap(); + assert!(current_max[0] > max_element_for_last_slab); + max_element_for_last_slab = current_max[0]; + } + assert_eq!(total_size, SIZE); + } +} diff --git a/thirdparty/rstar/src/algorithm/bulk_load/mod.rs b/thirdparty/rstar/src/algorithm/bulk_load/mod.rs new file mode 100644 index 0000000..43adad6 --- /dev/null +++ b/thirdparty/rstar/src/algorithm/bulk_load/mod.rs @@ -0,0 +1,4 @@ +mod bulk_load_sequential; +mod cluster_group_iterator; + +pub use self::bulk_load_sequential::bulk_load_sequential; diff --git a/thirdparty/rstar/src/algorithm/intersection_iterator.rs b/thirdparty/rstar/src/algorithm/intersection_iterator.rs new file mode 100644 index 0000000..3be3c55 --- /dev/null +++ b/thirdparty/rstar/src/algorithm/intersection_iterator.rs @@ -0,0 +1,156 @@ +use crate::node::ParentNode; +use crate::Envelope; +use crate::RTreeNode; +use crate::RTreeNode::*; +use crate::RTreeObject; + +#[cfg(not(test))] +use alloc::vec::Vec; +use core::mem::take; + +#[cfg(doc)] +use crate::RTree; + +/// Iterator returned by [`RTree::intersection_candidates_with_other_tree`]. +pub struct IntersectionIterator<'a, T, U = T> +where + T: RTreeObject, + U: RTreeObject, +{ + todo_list: Vec<(&'a RTreeNode, &'a RTreeNode)>, + candidates: Vec<&'a RTreeNode>, +} + +impl<'a, T, U> IntersectionIterator<'a, T, U> +where + T: RTreeObject, + U: RTreeObject, +{ + pub(crate) fn new(root1: &'a ParentNode, root2: &'a ParentNode) -> Self { + let mut intersections = IntersectionIterator { + todo_list: Vec::new(), + candidates: Vec::new(), + }; + intersections.add_intersecting_children(root1, root2); + intersections + } + + fn push_if_intersecting(&mut self, node1: &'a RTreeNode, node2: &'a RTreeNode) { + if node1.envelope().intersects(&node2.envelope()) { + self.todo_list.push((node1, node2)); + } + } + + fn add_intersecting_children( + &mut self, + parent1: &'a ParentNode, + parent2: &'a ParentNode, + ) { + if !parent1.envelope().intersects(&parent2.envelope()) { + return; + } + let children1 = parent1 + .children() + .iter() + .filter(|c1| c1.envelope().intersects(&parent2.envelope())); + + let mut children2 = take(&mut self.candidates); + children2.extend( + parent2 + .children() + .iter() + .filter(|c2| c2.envelope().intersects(&parent1.envelope())), + ); + + for child1 in children1 { + for child2 in &children2 { + self.push_if_intersecting(child1, child2); + } + } + + children2.clear(); + self.candidates = children2; + } +} + +impl<'a, T, U> Iterator for IntersectionIterator<'a, T, U> +where + T: RTreeObject, + U: RTreeObject, +{ + type Item = (&'a T, &'a U); + + fn next(&mut self) -> Option { + while let Some(next) = self.todo_list.pop() { + match next { + (Leaf(t1), Leaf(t2)) => return Some((t1, t2)), + (leaf @ Leaf(_), Parent(p)) => { + p.children() + .iter() + .for_each(|c| self.push_if_intersecting(leaf, c)); + } + (Parent(p), leaf @ Leaf(_)) => { + p.children() + .iter() + .for_each(|c| self.push_if_intersecting(c, leaf)); + } + (Parent(p1), Parent(p2)) => { + self.add_intersecting_children(p1, p2); + } + } + } + None + } +} + +#[cfg(test)] +mod test { + use crate::test_utilities::*; + use crate::{Envelope, RTree, RTreeObject}; + + #[test] + fn test_intersection_between_trees() { + let rectangles1 = create_random_rectangles(100, SEED_1); + let rectangles2 = create_random_rectangles(42, SEED_2); + + let mut intersections_brute_force = Vec::new(); + for rectangle1 in &rectangles1 { + for rectangle2 in &rectangles2 { + if rectangle1.envelope().intersects(&rectangle2.envelope()) { + intersections_brute_force.push((rectangle1, rectangle2)); + } + } + } + + let tree1 = RTree::bulk_load(rectangles1.clone()); + let tree2 = RTree::bulk_load(rectangles2.clone()); + let mut intersections_from_trees = tree1 + .intersection_candidates_with_other_tree(&tree2) + .collect::>(); + + intersections_brute_force.sort_by(|a, b| a.partial_cmp(b).unwrap()); + intersections_from_trees.sort_by(|a, b| a.partial_cmp(b).unwrap()); + assert_eq!(intersections_brute_force, intersections_from_trees); + } + + #[test] + fn test_trivial_intersections() { + let points1 = create_random_points(1000, SEED_1); + let points2 = create_random_points(2000, SEED_2); + let tree1 = RTree::bulk_load(points1); + let tree2 = RTree::bulk_load(points2); + + assert_eq!( + tree1 + .intersection_candidates_with_other_tree(&tree2) + .count(), + 0 + ); + assert_eq!( + tree1 + .intersection_candidates_with_other_tree(&tree1) + .count(), + tree1.size() + ); + } +} diff --git a/thirdparty/rstar/src/algorithm/iterators.rs b/thirdparty/rstar/src/algorithm/iterators.rs new file mode 100644 index 0000000..0000289 --- /dev/null +++ b/thirdparty/rstar/src/algorithm/iterators.rs @@ -0,0 +1,419 @@ +use crate::algorithm::selection_functions::*; +use crate::node::{ParentNode, RTreeNode}; +use crate::object::RTreeObject; +use core::ops::ControlFlow; + +#[cfg(doc)] +use crate::RTree; + +use smallvec::SmallVec; + +pub use super::intersection_iterator::IntersectionIterator; +pub use super::removal::{DrainIterator, IntoIter}; + +/// Iterator returned by [`RTree::locate_all_at_point`]. +pub type LocateAllAtPoint<'a, T> = SelectionIterator<'a, T, SelectAtPointFunction>; +/// Iterator returned by [`RTree::locate_all_at_point_mut`]. +pub type LocateAllAtPointMut<'a, T> = SelectionIteratorMut<'a, T, SelectAtPointFunction>; + +/// Iterator returned by [`RTree::locate_in_envelope`]. +pub type LocateInEnvelope<'a, T> = SelectionIterator<'a, T, SelectInEnvelopeFunction>; +/// Iterator returned by [`RTree::locate_in_envelope_mut`]. +pub type LocateInEnvelopeMut<'a, T> = SelectionIteratorMut<'a, T, SelectInEnvelopeFunction>; + +/// Iterator returned by [`RTree::locate_in_envelope_intersecting`]. +pub type LocateInEnvelopeIntersecting<'a, T> = + SelectionIterator<'a, T, SelectInEnvelopeFuncIntersecting>; +/// Iterator returned by [`RTree::locate_in_envelope_intersecting_mut`]. +pub type LocateInEnvelopeIntersectingMut<'a, T> = + SelectionIteratorMut<'a, T, SelectInEnvelopeFuncIntersecting>; + +/// Iterator returned by [`RTree::iter`]. +pub type RTreeIterator<'a, T> = SelectionIterator<'a, T, SelectAllFunc>; +/// Iterator returned by [`RTree::iter_mut`]. +pub type RTreeIteratorMut<'a, T> = SelectionIteratorMut<'a, T, SelectAllFunc>; + +/// Iterator returned by [`RTree::locate_within_distance`]. +pub type LocateWithinDistanceIterator<'a, T> = + SelectionIterator<'a, T, SelectWithinDistanceFunction>; + +/// Iterator returned by `RTree::locate_*` methods. +pub struct SelectionIterator<'a, T, Func> +where + T: RTreeObject + 'a, + Func: SelectionFunction, +{ + func: Func, + current_nodes: SmallVec<[&'a RTreeNode; 24]>, +} + +impl<'a, T, Func> SelectionIterator<'a, T, Func> +where + T: RTreeObject, + Func: SelectionFunction, +{ + pub(crate) fn new(root: &'a ParentNode, func: Func) -> Self { + let current_nodes = + if !root.children.is_empty() && func.should_unpack_parent(&root.envelope()) { + root.children.iter().collect() + } else { + SmallVec::new() + }; + + SelectionIterator { + func, + current_nodes, + } + } +} + +impl<'a, T, Func> Iterator for SelectionIterator<'a, T, Func> +where + T: RTreeObject, + Func: SelectionFunction, +{ + type Item = &'a T; + + fn next(&mut self) -> Option<&'a T> { + while let Some(next) = self.current_nodes.pop() { + match next { + RTreeNode::Leaf(ref t) => { + if self.func.should_unpack_leaf(t) { + return Some(t); + } + } + RTreeNode::Parent(ref data) => { + if self.func.should_unpack_parent(&data.envelope) { + self.current_nodes.extend(&data.children); + } + } + } + } + None + } +} + +/// Internal iteration variant of [`SelectionIterator`] +pub fn select_nodes<'a, T, Func, V, B>( + root: &'a ParentNode, + func: &Func, + visitor: &mut V, +) -> ControlFlow +where + T: RTreeObject, + Func: SelectionFunction, + V: FnMut(&'a T) -> ControlFlow, +{ + struct Args<'a, Func, V> { + func: &'a Func, + visitor: &'a mut V, + } + + fn inner<'a, T, Func, V, B>( + parent: &'a ParentNode, + args: &mut Args<'_, Func, V>, + ) -> ControlFlow + where + T: RTreeObject, + Func: SelectionFunction, + V: FnMut(&'a T) -> ControlFlow, + { + for node in parent.children.iter() { + match node { + RTreeNode::Leaf(ref t) => { + if args.func.should_unpack_leaf(t) { + (args.visitor)(t)?; + } + } + RTreeNode::Parent(ref data) => { + if args.func.should_unpack_parent(&data.envelope()) { + inner(data, args)?; + } + } + } + } + + ControlFlow::Continue(()) + } + + if !root.children.is_empty() && func.should_unpack_parent(&root.envelope()) { + inner(root, &mut Args { func, visitor })?; + } + + ControlFlow::Continue(()) +} + +/// Iterator type returned by `RTree::locate_*_mut` methods. +pub struct SelectionIteratorMut<'a, T, Func> +where + T: RTreeObject + 'a, + Func: SelectionFunction, +{ + func: Func, + current_nodes: SmallVec<[&'a mut RTreeNode; 32]>, +} + +impl<'a, T, Func> SelectionIteratorMut<'a, T, Func> +where + T: RTreeObject, + Func: SelectionFunction, +{ + pub(crate) fn new(root: &'a mut ParentNode, func: Func) -> Self { + let current_nodes = + if !root.children.is_empty() && func.should_unpack_parent(&root.envelope()) { + root.children.iter_mut().collect() + } else { + SmallVec::new() + }; + + SelectionIteratorMut { + func, + current_nodes, + } + } +} + +impl<'a, T, Func> Iterator for SelectionIteratorMut<'a, T, Func> +where + T: RTreeObject, + Func: SelectionFunction, +{ + type Item = &'a mut T; + + fn next(&mut self) -> Option<&'a mut T> { + while let Some(next) = self.current_nodes.pop() { + match next { + RTreeNode::Leaf(ref mut t) => { + if self.func.should_unpack_leaf(t) { + return Some(t); + } + } + RTreeNode::Parent(ref mut data) => { + if self.func.should_unpack_parent(&data.envelope) { + self.current_nodes.extend(&mut data.children); + } + } + } + } + None + } +} + +/// Internal iteration variant of [`SelectionIteratorMut`] +pub fn select_nodes_mut<'a, T, Func, V, B>( + root: &'a mut ParentNode, + func: &Func, + visitor: &mut V, +) -> ControlFlow +where + T: RTreeObject, + Func: SelectionFunction, + V: FnMut(&'a mut T) -> ControlFlow, +{ + struct Args<'a, Func, V> { + func: &'a Func, + visitor: &'a mut V, + } + + fn inner<'a, T, Func, V, B>( + parent: &'a mut ParentNode, + args: &mut Args<'_, Func, V>, + ) -> ControlFlow + where + T: RTreeObject, + Func: SelectionFunction, + V: FnMut(&'a mut T) -> ControlFlow, + { + for node in parent.children.iter_mut() { + match node { + RTreeNode::Leaf(ref mut t) => { + if args.func.should_unpack_leaf(t) { + (args.visitor)(t)?; + } + } + RTreeNode::Parent(ref mut data) => { + if args.func.should_unpack_parent(&data.envelope()) { + inner(data, args)?; + } + } + } + } + + ControlFlow::Continue(()) + } + + if !root.children.is_empty() && func.should_unpack_parent(&root.envelope()) { + inner(root, &mut Args { func, visitor })?; + } + + ControlFlow::Continue(()) +} + +#[cfg(test)] +mod test { + use crate::aabb::AABB; + use crate::envelope::Envelope; + use crate::object::RTreeObject; + use crate::rtree::RTree; + use crate::test_utilities::{create_random_points, create_random_rectangles, SEED_1}; + use crate::SelectionFunction; + + #[test] + fn test_root_node_is_not_always_unpacked() { + struct SelectNoneFunc {} + + impl SelectionFunction<[i32; 2]> for SelectNoneFunc { + fn should_unpack_parent(&self, _: &AABB<[i32; 2]>) -> bool { + false + } + } + + let mut tree = RTree::bulk_load(vec![[0i32, 0]]); + + let mut elements = tree.locate_with_selection_function(SelectNoneFunc {}); + assert!(elements.next().is_none()); + drop(elements); + + let mut elements = tree.locate_with_selection_function_mut(SelectNoneFunc {}); + assert!(elements.next().is_none()); + } + + #[test] + fn test_locate_all() { + const NUM_RECTANGLES: usize = 400; + let rectangles = create_random_rectangles(NUM_RECTANGLES, SEED_1); + let tree = RTree::bulk_load(rectangles.clone()); + + let query_points = create_random_points(20, SEED_1); + + for p in &query_points { + let contained_sequential: Vec<_> = rectangles + .iter() + .filter(|rectangle| rectangle.envelope().contains_point(p)) + .cloned() + .collect(); + + let contained_rtree: Vec<_> = tree.locate_all_at_point(p).cloned().collect(); + + contained_sequential + .iter() + .all(|r| contained_rtree.contains(r)); + contained_rtree + .iter() + .all(|r| contained_sequential.contains(r)); + } + } + + #[test] + fn test_locate_in_envelope() { + let points = create_random_points(100, SEED_1); + let tree = RTree::bulk_load(points.clone()); + let envelope = AABB::from_corners([0.5, 0.5], [1.0, 1.0]); + let contained_in_envelope: Vec<_> = points + .iter() + .filter(|point| envelope.contains_point(point)) + .cloned() + .collect(); + let len = contained_in_envelope.len(); + assert!(10 < len && len < 90, "unexpected point distribution"); + let located: Vec<_> = tree.locate_in_envelope(&envelope).cloned().collect(); + assert_eq!(len, located.len()); + for point in &contained_in_envelope { + assert!(located.contains(point)); + } + } + + #[test] + fn test_locate_with_selection_func() { + use crate::SelectionFunction; + + struct SelectLeftOfZeroPointFiveFunc; + + impl SelectionFunction<[f64; 2]> for SelectLeftOfZeroPointFiveFunc { + fn should_unpack_parent(&self, parent_envelope: &AABB<[f64; 2]>) -> bool { + parent_envelope.lower()[0] < 0.5 || parent_envelope.upper()[0] < 0.5 + } + + fn should_unpack_leaf(&self, child: &[f64; 2]) -> bool { + child[0] < 0.5 + } + } + + let func = SelectLeftOfZeroPointFiveFunc; + + let points = create_random_points(100, SEED_1); + let tree = RTree::bulk_load(points.clone()); + let iterative_count = points + .iter() + .filter(|leaf| func.should_unpack_leaf(leaf)) + .count(); + let selected = tree + .locate_with_selection_function(func) + .collect::>(); + + assert_eq!(iterative_count, selected.len()); + assert!(iterative_count > 20); // Make sure that we do test something interesting + for point in &selected { + assert!(point[0] < 0.5); + } + } + + #[test] + fn test_iteration() { + const NUM_POINTS: usize = 1000; + let points = create_random_points(NUM_POINTS, SEED_1); + let mut tree = RTree::new(); + for p in &points { + tree.insert(*p); + } + let mut count = 0usize; + for p in tree.iter() { + assert!(points.iter().any(|q| q == p)); + count += 1; + } + assert_eq!(count, NUM_POINTS); + count = 0; + for p in tree.iter_mut() { + assert!(points.iter().any(|q| q == p)); + count += 1; + } + assert_eq!(count, NUM_POINTS); + for p in &points { + assert!(tree.iter().any(|q| q == p)); + assert!(tree.iter_mut().any(|q| q == p)); + } + } + + #[test] + fn test_locate_within_distance() { + use crate::primitives::Line; + + let points = create_random_points(100, SEED_1); + let tree = RTree::bulk_load(points.clone()); + let circle_radius_2 = 0.3; + let circle_origin = [0.2, 0.6]; + let contained_in_circle: Vec<_> = points + .iter() + .filter(|point| Line::new(circle_origin, **point).length_2() <= circle_radius_2) + .cloned() + .collect(); + let located: Vec<_> = tree + .locate_within_distance(circle_origin, circle_radius_2) + .cloned() + .collect(); + + assert_eq!(located.len(), contained_in_circle.len()); + for point in &contained_in_circle { + assert!(located.contains(point)); + } + } + + #[test] + fn test_locate_within_distance_on_empty_tree() { + let tree: RTree<[f64; 3]> = RTree::new(); + tree.locate_within_distance([0.0, 0.0, 0.0], 10.0); + + let tree: RTree<[i64; 3]> = RTree::new(); + tree.locate_within_distance([0, 0, 0], 10); + } +} diff --git a/thirdparty/rstar/src/algorithm/mod.rs b/thirdparty/rstar/src/algorithm/mod.rs new file mode 100644 index 0000000..cdaed99 --- /dev/null +++ b/thirdparty/rstar/src/algorithm/mod.rs @@ -0,0 +1,8 @@ +pub mod bulk_load; +pub mod intersection_iterator; +/// Iterator types +pub mod iterators; +pub mod nearest_neighbor; +pub mod removal; +pub mod rstar; +pub mod selection_functions; diff --git a/thirdparty/rstar/src/algorithm/nearest_neighbor.rs b/thirdparty/rstar/src/algorithm/nearest_neighbor.rs new file mode 100644 index 0000000..698b26d --- /dev/null +++ b/thirdparty/rstar/src/algorithm/nearest_neighbor.rs @@ -0,0 +1,405 @@ +use crate::node::{ParentNode, RTreeNode}; +use crate::point::{min_inline, Point}; +use crate::{Envelope, PointDistance, RTreeObject}; + +use alloc::collections::BinaryHeap; +#[cfg(not(test))] +use alloc::{vec, vec::Vec}; +use core::mem::replace; +use heapless::binary_heap as static_heap; +use num_traits::Bounded; + +struct RTreeNodeDistanceWrapper<'a, T> +where + T: PointDistance + 'a, +{ + node: &'a RTreeNode, + distance: <::Point as Point>::Scalar, +} + +impl<'a, T> PartialEq for RTreeNodeDistanceWrapper<'a, T> +where + T: PointDistance, +{ + fn eq(&self, other: &Self) -> bool { + self.distance == other.distance + } +} + +impl<'a, T> PartialOrd for RTreeNodeDistanceWrapper<'a, T> +where + T: PointDistance, +{ + fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> { + Some(self.cmp(other)) + } +} + +impl<'a, T> Eq for RTreeNodeDistanceWrapper<'a, T> where T: PointDistance {} + +impl<'a, T> Ord for RTreeNodeDistanceWrapper<'a, T> +where + T: PointDistance, +{ + fn cmp(&self, other: &Self) -> ::core::cmp::Ordering { + // Inverse comparison creates a min heap + other.distance.partial_cmp(&self.distance).unwrap() + } +} + +impl<'a, T> NearestNeighborDistance2Iterator<'a, T> +where + T: PointDistance, +{ + pub fn new(root: &'a ParentNode, query_point: ::Point) -> Self { + let mut result = NearestNeighborDistance2Iterator { + nodes: SmallHeap::new(), + query_point, + }; + result.extend_heap(&root.children); + result + } + + fn extend_heap(&mut self, children: &'a [RTreeNode]) { + let &mut NearestNeighborDistance2Iterator { + ref mut nodes, + ref query_point, + } = self; + nodes.extend(children.iter().map(|child| { + let distance = match child { + RTreeNode::Parent(ref data) => data.envelope.distance_2(query_point), + RTreeNode::Leaf(ref t) => t.distance_2(query_point), + }; + + RTreeNodeDistanceWrapper { + node: child, + distance, + } + })); + } +} + +impl<'a, T> Iterator for NearestNeighborDistance2Iterator<'a, T> +where + T: PointDistance, +{ + type Item = (&'a T, <::Point as Point>::Scalar); + + fn next(&mut self) -> Option { + while let Some(current) = self.nodes.pop() { + match current { + RTreeNodeDistanceWrapper { + node: RTreeNode::Parent(ref data), + .. + } => { + self.extend_heap(&data.children); + } + RTreeNodeDistanceWrapper { + node: RTreeNode::Leaf(ref t), + distance, + } => { + return Some((t, distance)); + } + } + } + None + } +} + +pub struct NearestNeighborDistance2Iterator<'a, T> +where + T: PointDistance + 'a, +{ + nodes: SmallHeap>, + query_point: ::Point, +} + +impl<'a, T> NearestNeighborIterator<'a, T> +where + T: PointDistance, +{ + pub fn new(root: &'a ParentNode, query_point: ::Point) -> Self { + NearestNeighborIterator { + iter: NearestNeighborDistance2Iterator::new(root, query_point), + } + } +} + +impl<'a, T> Iterator for NearestNeighborIterator<'a, T> +where + T: PointDistance, +{ + type Item = &'a T; + + fn next(&mut self) -> Option { + self.iter.next().map(|(t, _distance)| t) + } +} + +pub struct NearestNeighborIterator<'a, T> +where + T: PointDistance + 'a, +{ + iter: NearestNeighborDistance2Iterator<'a, T>, +} + +enum SmallHeap { + Stack(static_heap::BinaryHeap), + Heap(BinaryHeap), +} + +impl SmallHeap { + pub fn new() -> Self { + Self::Stack(static_heap::BinaryHeap::new()) + } + + pub fn pop(&mut self) -> Option { + match self { + SmallHeap::Stack(heap) => heap.pop(), + SmallHeap::Heap(heap) => heap.pop(), + } + } + + pub fn push(&mut self, item: T) { + match self { + SmallHeap::Stack(heap) => { + if let Err(item) = heap.push(item) { + let capacity = heap.len() + 1; + let new_heap = self.spill(capacity); + new_heap.push(item); + } + } + SmallHeap::Heap(heap) => heap.push(item), + } + } + + pub fn extend(&mut self, iter: I) + where + I: ExactSizeIterator, + { + match self { + SmallHeap::Stack(heap) => { + if heap.capacity() >= heap.len() + iter.len() { + for item in iter { + if heap.push(item).is_err() { + unreachable!(); + } + } + } else { + let capacity = heap.len() + iter.len(); + let new_heap = self.spill(capacity); + new_heap.extend(iter); + } + } + SmallHeap::Heap(heap) => heap.extend(iter), + } + } + + #[cold] + fn spill(&mut self, capacity: usize) -> &mut BinaryHeap { + let new_heap = BinaryHeap::with_capacity(capacity); + let old_heap = replace(self, SmallHeap::Heap(new_heap)); + + let new_heap = match self { + SmallHeap::Heap(new_heap) => new_heap, + SmallHeap::Stack(_) => unreachable!(), + }; + let old_heap = match old_heap { + SmallHeap::Stack(old_heap) => old_heap, + SmallHeap::Heap(_) => unreachable!(), + }; + + new_heap.extend(old_heap.into_vec()); + + new_heap + } +} + +pub fn nearest_neighbor( + node: &ParentNode, + query_point: ::Point, +) -> Option<&T> +where + T: PointDistance, +{ + fn extend_heap<'a, T>( + nodes: &mut SmallHeap>, + node: &'a ParentNode, + query_point: ::Point, + min_max_distance: &mut <::Point as Point>::Scalar, + ) where + T: PointDistance + 'a, + { + for child in &node.children { + let distance_if_less_or_equal = match child { + RTreeNode::Parent(ref data) => { + let distance = data.envelope.distance_2(&query_point); + if distance <= *min_max_distance { + Some(distance) + } else { + None + } + } + RTreeNode::Leaf(ref t) => { + t.distance_2_if_less_or_equal(&query_point, *min_max_distance) + } + }; + if let Some(distance) = distance_if_less_or_equal { + *min_max_distance = min_inline( + *min_max_distance, + child.envelope().min_max_dist_2(&query_point), + ); + nodes.push(RTreeNodeDistanceWrapper { + node: child, + distance, + }); + } + } + } + + // Calculate smallest minmax-distance + let mut smallest_min_max: <::Point as Point>::Scalar = + Bounded::max_value(); + let mut nodes = SmallHeap::new(); + extend_heap(&mut nodes, node, query_point.clone(), &mut smallest_min_max); + while let Some(current) = nodes.pop() { + match current { + RTreeNodeDistanceWrapper { + node: RTreeNode::Parent(ref data), + .. + } => { + extend_heap(&mut nodes, data, query_point.clone(), &mut smallest_min_max); + } + RTreeNodeDistanceWrapper { + node: RTreeNode::Leaf(ref t), + .. + } => { + return Some(t); + } + } + } + None +} + +pub fn nearest_neighbors( + node: &ParentNode, + query_point: ::Point, +) -> Vec<&T> +where + T: PointDistance, +{ + let mut nearest_neighbors = NearestNeighborDistance2Iterator::new(node, query_point.clone()); + + let (first, first_distance_2) = match nearest_neighbors.next() { + Some(item) => item, + // If we have an empty tree, just return an empty vector. + None => return Vec::new(), + }; + + // The result will at least contain the first nearest neighbor. + let mut result = vec![first]; + + // Use the distance to the first nearest neighbor + // to filter out the rest of the nearest neighbors + // that are farther than this first neighbor. + result.extend( + nearest_neighbors + .take_while(|(_, next_distance_2)| next_distance_2 == &first_distance_2) + .map(|(next, _)| next), + ); + + result +} + +#[cfg(test)] +mod test { + use crate::object::PointDistance; + use crate::rtree::RTree; + use crate::test_utilities::*; + + #[test] + fn test_nearest_neighbor_empty() { + let tree: RTree<[f32; 2]> = RTree::new(); + assert!(tree.nearest_neighbor(&[0.0, 213.0]).is_none()); + } + + #[test] + fn test_nearest_neighbor() { + let points = create_random_points(1000, SEED_1); + let tree = RTree::bulk_load(points.clone()); + + let sample_points = create_random_points(100, SEED_2); + for sample_point in &sample_points { + let mut nearest = None; + let mut closest_dist = f64::INFINITY; + for point in &points { + let delta = [point[0] - sample_point[0], point[1] - sample_point[1]]; + let new_dist = delta[0] * delta[0] + delta[1] * delta[1]; + if new_dist < closest_dist { + closest_dist = new_dist; + nearest = Some(point); + } + } + assert_eq!(nearest, tree.nearest_neighbor(sample_point)); + } + } + + #[test] + fn test_nearest_neighbors_empty() { + let tree: RTree<[f32; 2]> = RTree::new(); + assert!(tree.nearest_neighbors(&[0.0, 213.0]).is_empty()); + } + + #[test] + fn test_nearest_neighbors() { + let points = create_random_points(1000, SEED_1); + let tree = RTree::bulk_load(points); + + let sample_points = create_random_points(50, SEED_2); + for sample_point in &sample_points { + let nearest_neighbors = tree.nearest_neighbors(sample_point); + let mut distance = -1.0; + for nn in &nearest_neighbors { + if distance < 0.0 { + distance = sample_point.distance_2(nn); + } else { + let new_distance = sample_point.distance_2(nn); + assert_eq!(new_distance, distance); + } + } + } + } + + #[test] + fn test_nearest_neighbor_iterator() { + let mut points = create_random_points(1000, SEED_1); + let tree = RTree::bulk_load(points.clone()); + + let sample_points = create_random_points(50, SEED_2); + for sample_point in &sample_points { + points.sort_by(|r, l| { + r.distance_2(sample_point) + .partial_cmp(&l.distance_2(sample_point)) + .unwrap() + }); + let collected: Vec<_> = tree.nearest_neighbor_iter(sample_point).cloned().collect(); + assert_eq!(points, collected); + } + } + + #[test] + fn test_nearest_neighbor_iterator_with_distance_2() { + let points = create_random_points(1000, SEED_2); + let tree = RTree::bulk_load(points); + + let sample_points = create_random_points(50, SEED_1); + for sample_point in &sample_points { + let mut last_distance = 0.0; + for (point, distance) in tree.nearest_neighbor_iter_with_distance_2(sample_point) { + assert_eq!(point.distance_2(sample_point), distance); + assert!(last_distance < distance); + last_distance = distance; + } + } + } +} diff --git a/thirdparty/rstar/src/algorithm/removal.rs b/thirdparty/rstar/src/algorithm/removal.rs new file mode 100644 index 0000000..0bf5baa --- /dev/null +++ b/thirdparty/rstar/src/algorithm/removal.rs @@ -0,0 +1,397 @@ +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}; + +#[cfg(not(test))] +use alloc::{vec, vec::Vec}; + +#[allow(unused_imports)] // Import is required when building without std +use num_traits::Float; + +/// Iterator returned by `impl IntoIter for RTree`. +/// +/// Consumes the whole tree and yields all leaf objects. +pub struct IntoIter +where + T: RTreeObject, +{ + node_stack: Vec>, +} + +impl IntoIter +where + T: RTreeObject, +{ + pub(crate) fn new(root: ParentNode) -> Self { + Self { + node_stack: vec![RTreeNode::Parent(root)], + } + } +} + +impl Iterator for IntoIter +where + T: RTreeObject, +{ + type Item = T; + + fn next(&mut self) -> Option { + while let Some(node) = self.node_stack.pop() { + match node { + RTreeNode::Leaf(object) => return Some(object), + RTreeNode::Parent(parent) => self.node_stack.extend(parent.children), + } + } + + None + } +} + +/// Iterator returned by `RTree::drain_*` methods. +/// +/// Draining iterator that removes elements of the tree selected by a +/// [`SelectionFunction`]. Returned by +/// [`RTree::drain_with_selection_function`] and related methods. +/// +/// # Remarks +/// +/// This iterator is similar to the one returned by `Vec::drain` or +/// `Vec::drain_filter`. Dropping the iterator at any point removes only +/// 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> +where + T: RTreeObject, + Params: RTreeParams, + R: SelectionFunction, +{ + node_stack: Vec<(ParentNode, usize, usize)>, + removal_function: R, + rtree: &'a mut RTree, + original_size: usize, +} + +impl<'a, T, R, Params> DrainIterator<'a, T, R, Params> +where + T: RTreeObject, + Params: RTreeParams, + R: SelectionFunction, +{ + 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. + + // Instead of using `new_with_params`, we avoid an allocation for + // the normal usage and replace root with an empty `Vec`. + let root = replace( + rtree.root_mut(), + ParentNode { + children: vec![], + envelope: Envelope::new_empty(), + }, + ); + let original_size = replace(rtree.size_mut(), 0); + + let m = 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)); + + DrainIterator { + node_stack, + original_size, + removal_function, + rtree, + } + } + + fn pop_node(&mut self, increment_idx: bool) -> Option<(ParentNode, usize)> { + debug_assert!(!self.node_stack.is_empty()); + + let (mut node, _, num_removed) = self.node_stack.pop().unwrap(); + + // We only compute envelope for the current node as the parent + // is taken care of when it is popped. + + // TODO: May be make this a method on `ParentNode` + if num_removed > 0 { + node.envelope = crate::node::envelope_for_children(&node.children); + } + + // If there is no parent, this is the new root node to set back in the rtree + // O/w, get the new top in stack + let (parent_node, parent_idx, parent_removed) = match self.node_stack.last_mut() { + Some(pn) => (&mut pn.0, &mut pn.1, &mut pn.2), + None => return Some((node, num_removed)), + }; + + // Update the remove count on parent + *parent_removed += num_removed; + + // If the node has no children, we don't need to add it back to the parent + if node.children.is_empty() { + return None; + } + + // Put the child back (but re-arranged) + parent_node.children.push(RTreeNode::Parent(node)); + + // Swap it with the current item and increment idx. + + // A minor optimization is to avoid the swap in the destructor, + // where we aren't going to be iterating any more. + if !increment_idx { + return None; + } + + // Note that during iteration, parent_idx may be equal to + // (previous) children.len(), but this is okay as the swap will be + // a no-op. + let parent_len = parent_node.children.len(); + parent_node.children.swap(*parent_idx, parent_len - 1); + *parent_idx += 1; + + None + } +} + +impl<'a, T, R, Params> Iterator for DrainIterator<'a, T, R, Params> +where + T: RTreeObject, + Params: RTreeParams, + R: SelectionFunction, +{ + type Item = T; + + fn next(&mut self) -> Option { + 'attempt_loop: loop { + // Get reference to top node or return None. + let (node, idx, remove_count) = match self.node_stack.last_mut() { + Some(node) => (&mut node.0, &mut node.1, &mut node.2), + None => return None, + }; + + // Try to find a selected item to return. + if *idx > 0 || self.removal_function.should_unpack_parent(&node.envelope) { + while *idx < node.children.len() { + match &mut node.children[*idx] { + RTreeNode::Parent(_) => { + // Swap node with last, remove and return the value. + // No need to increment idx as something else has replaced it; + // or idx == new len, and we'll handle it in the next iteration. + let child = match node.children.swap_remove(*idx) { + RTreeNode::Leaf(_) => unreachable!("DrainIterator bug!"), + RTreeNode::Parent(node) => node, + }; + self.node_stack.push((child, 0, 0)); + continue 'attempt_loop; + } + RTreeNode::Leaf(ref leaf) => { + if self.removal_function.should_unpack_leaf(leaf) { + // Swap node with last, remove and return the value. + // No need to increment idx as something else has replaced it; + // or idx == new len, and we'll handle it in the next iteration. + *remove_count += 1; + return match node.children.swap_remove(*idx) { + RTreeNode::Leaf(data) => Some(data), + _ => unreachable!("RemovalIterator bug!"), + }; + } + *idx += 1; + } + } + } + } + + // Pop top node and clean-up if done + if let Some((new_root, total_removed)) = self.pop_node(true) { + // This happens if we are done with the iteration. + // Set the root back in rtree and return None + *self.rtree.root_mut() = new_root; + *self.rtree.size_mut() = self.original_size - total_removed; + return None; + } + } + } +} + +impl<'a, T, R, Params> Drop for DrainIterator<'a, T, R, Params> +where + T: RTreeObject, + Params: RTreeParams, + R: SelectionFunction, +{ + fn drop(&mut self) { + // Re-assemble back the original rtree and update envelope as we + // re-assemble. + if self.node_stack.is_empty() { + // The iteration handled everything, nothing to do. + return; + } + + loop { + debug_assert!(!self.node_stack.is_empty()); + if let Some((new_root, total_removed)) = self.pop_node(false) { + *self.rtree.root_mut() = new_root; + *self.rtree.size_mut() = self.original_size - total_removed; + break; + } + } + } +} + +#[cfg(test)] +mod test { + use std::mem::forget; + + use crate::algorithm::selection_functions::{SelectAllFunc, SelectInEnvelopeFuncIntersecting}; + use crate::point::PointExt; + use crate::primitives::Line; + use crate::test_utilities::{create_random_points, create_random_rectangles, SEED_1, SEED_2}; + use crate::AABB; + + use super::*; + + #[test] + fn test_remove_and_insert() { + const SIZE: usize = 1000; + let points = create_random_points(SIZE, SEED_1); + let later_insertions = create_random_points(SIZE, SEED_2); + let mut tree = RTree::bulk_load(points.clone()); + for (point_to_remove, point_to_add) in points.iter().zip(later_insertions.iter()) { + assert!(tree.remove_at_point(point_to_remove).is_some()); + tree.insert(*point_to_add); + } + assert_eq!(tree.size(), SIZE); + assert!(points.iter().all(|p| !tree.contains(p))); + assert!(later_insertions.iter().all(|p| tree.contains(p))); + for point in &later_insertions { + assert!(tree.remove_at_point(point).is_some()); + } + assert_eq!(tree.size(), 0); + } + + #[test] + fn test_remove_and_insert_rectangles() { + const SIZE: usize = 1000; + let initial_rectangles = create_random_rectangles(SIZE, SEED_1); + let new_rectangles = create_random_rectangles(SIZE, SEED_2); + let mut tree = RTree::bulk_load(initial_rectangles.clone()); + + for (rectangle_to_remove, rectangle_to_add) in + initial_rectangles.iter().zip(new_rectangles.iter()) + { + assert!(tree.remove(rectangle_to_remove).is_some()); + tree.insert(*rectangle_to_add); + } + assert_eq!(tree.size(), SIZE); + assert!(initial_rectangles.iter().all(|p| !tree.contains(p))); + assert!(new_rectangles.iter().all(|p| tree.contains(p))); + for rectangle in &new_rectangles { + assert!(tree.contains(rectangle)); + } + for rectangle in &initial_rectangles { + assert!(!tree.contains(rectangle)); + } + for rectangle in &new_rectangles { + assert!(tree.remove(rectangle).is_some()); + } + assert_eq!(tree.size(), 0); + } + + #[test] + fn test_remove_at_point() { + let points = create_random_points(1000, SEED_1); + let mut tree = RTree::bulk_load(points.clone()); + for point in &points { + let size_before_removal = tree.size(); + assert!(tree.remove_at_point(point).is_some()); + assert!(tree.remove_at_point(&[1000.0, 1000.0]).is_none()); + assert_eq!(size_before_removal - 1, tree.size()); + } + } + + #[test] + fn test_remove() { + let points = create_random_points(1000, SEED_1); + let offsets = create_random_points(1000, SEED_2); + let scaled = offsets.iter().map(|p| p.mul(0.05)); + let edges: Vec<_> = points + .iter() + .zip(scaled) + .map(|(from, offset)| Line::new(*from, from.add(&offset))) + .collect(); + let mut tree = RTree::bulk_load(edges.clone()); + for edge in &edges { + let size_before_removal = tree.size(); + assert!(tree.remove(edge).is_some()); + assert!(tree.remove(edge).is_none()); + assert_eq!(size_before_removal - 1, tree.size()); + } + } + + #[test] + fn test_drain_iterator() { + const SIZE: usize = 1000; + let points = create_random_points(SIZE, SEED_1); + let mut tree = RTree::bulk_load(points); + + let drain_count = DrainIterator::new(&mut tree, SelectAllFunc) + .take(250) + .count(); + assert_eq!(drain_count, 250); + assert_eq!(tree.size(), 750); + + let drain_count = DrainIterator::new(&mut tree, SelectAllFunc) + .take(250) + .count(); + assert_eq!(drain_count, 250); + assert_eq!(tree.size(), 500); + + // Test Drain forget soundness + forget(DrainIterator::new(&mut tree, SelectAllFunc)); + // Check tree has no nodes + // Tests below will check the same tree can be used again + assert_eq!(tree.size(), 0); + + let points = create_random_points(1000, SEED_1); + points.into_iter().for_each(|pt| tree.insert(pt)); + + // The total for this is 406 (for SEED_1) + let env = AABB::from_corners([-2., -0.6], [0.5, 0.85]); + + let sel = SelectInEnvelopeFuncIntersecting::new(env); + let drain_count = DrainIterator::new(&mut tree, sel).take(80).count(); + assert_eq!(drain_count, 80); + + let sel = SelectInEnvelopeFuncIntersecting::new(env); + let drain_count = DrainIterator::new(&mut tree, sel).count(); + assert_eq!(drain_count, 326); + + let sel = SelectInEnvelopeFuncIntersecting::new(env); + let sel_count = tree.locate_with_selection_function(sel).count(); + assert_eq!(sel_count, 0); + assert_eq!(tree.size(), 1000 - 80 - 326); + } + + #[test] + fn test_into_iter() { + const SIZE: usize = 100; + let mut points = create_random_points(SIZE, SEED_1); + let tree = RTree::bulk_load(points.clone()); + + let mut vec = tree.into_iter().collect::>(); + + assert_eq!(vec.len(), points.len()); + + points.sort_unstable_by(|lhs, rhs| lhs.partial_cmp(rhs).unwrap()); + vec.sort_unstable_by(|lhs, rhs| lhs.partial_cmp(rhs).unwrap()); + + assert_eq!(points, vec); + } +} diff --git a/thirdparty/rstar/src/algorithm/rstar.rs b/thirdparty/rstar/src/algorithm/rstar.rs new file mode 100644 index 0000000..9127037 --- /dev/null +++ b/thirdparty/rstar/src/algorithm/rstar.rs @@ -0,0 +1,354 @@ +use crate::envelope::Envelope; +use crate::node::{envelope_for_children, ParentNode, RTreeNode}; +use crate::object::RTreeObject; +use crate::params::{InsertionStrategy, RTreeParams}; +use crate::point::{Point, PointExt}; +use crate::rtree::RTree; + +#[cfg(not(test))] +use alloc::vec::Vec; +use num_traits::{Bounded, Zero}; + +/// Inserts points according to the r-star heuristic. +/// +/// The r*-heuristic focusses on good insertion quality at the costs of +/// insertion performance. This strategy is best for use cases with few +/// insertions and many nearest neighbor queries. +/// +/// `RStarInsertionStrategy` is used as the default insertion strategy. +/// See [InsertionStrategy] for more information on insertion strategies. +pub enum RStarInsertionStrategy {} + +enum InsertionResult +where + T: RTreeObject, +{ + Split(RTreeNode), + Reinsert(Vec>, usize), + Complete, +} + +impl InsertionStrategy for RStarInsertionStrategy { + fn insert(tree: &mut RTree, t: T) + where + Params: RTreeParams, + T: RTreeObject, + { + use InsertionAction::*; + + enum InsertionAction { + PerformSplit(RTreeNode), + PerformReinsert(RTreeNode), + } + + 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; + } + 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 => {} + } + } + } + } + } +} + +fn forced_insertion( + 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); + + 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); + } + + if let RTreeNode::Parent(ref mut follow) = node.children[expand_index] { + 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) + } + other => other, + } + } else { + unreachable!("This is a bug in rstar.") + } +} + +fn recursive_insert( + 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); + + if node.children.len() < expand_index { + // Force insertion into this node + node.children.push(t); + 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) + } else { + panic!("This is a bug in rstar.") + }; + + match expand { + InsertionResult::Split(child) => { + node.envelope.merge(&child.envelope()); + node.children.push(child); + resolve_overflow::<_, Params>(node, current_height) + } + InsertionResult::Reinsert(a, b) => { + node.envelope = envelope_for_children(&node.children); + InsertionResult::Reinsert(a, b) + } + other => other, + } +} + +fn choose_subtree(node: &ParentNode, to_insert: &RTreeNode) -> usize +where + T: RTreeObject, +{ + let all_leaves = match node.children.first() { + Some(RTreeNode::Leaf(_)) => return usize::MAX, + Some(RTreeNode::Parent(ref data)) => data + .children + .first() + .map(RTreeNode::is_leaf) + .unwrap_or(true), + None => return usize::MAX, + }; + + let zero: <::Point as Point>::Scalar = Zero::zero(); + let insertion_envelope = to_insert.envelope(); + let mut inclusion_count = 0; + let mut min_area = <::Point as Point>::Scalar::max_value(); + let mut min_index = 0; + for (index, child) in node.children.iter().enumerate() { + let envelope = child.envelope(); + if envelope.contains_envelope(&insertion_envelope) { + inclusion_count += 1; + let area = envelope.area(); + if area < min_area { + min_area = area; + min_index = index; + } + } + } + if inclusion_count == 0 { + // No inclusion found, subtree depends on overlap and area increase + let mut min = (zero, zero, zero); + + for (index, child1) in node.children.iter().enumerate() { + let envelope = child1.envelope(); + let mut new_envelope = envelope.clone(); + new_envelope.merge(&insertion_envelope); + let overlap_increase = if all_leaves { + // Calculate minimal overlap increase + let mut overlap = zero; + let mut new_overlap = zero; + for child2 in &node.children { + if child1 as *const _ != child2 as *const _ { + let child_envelope = child2.envelope(); + let temp1 = envelope.intersection_area(&child_envelope); + overlap = overlap + temp1; + let temp2 = new_envelope.intersection_area(&child_envelope); + new_overlap = new_overlap + temp2; + } + } + new_overlap - overlap + } else { + // Don't calculate overlap increase if not all children are leaves + zero + }; + // Calculate area increase and area + let area = new_envelope.area(); + let area_increase = area - envelope.area(); + let new_min = (overlap_increase, area_increase, area); + if new_min < min || index == 0 { + min = new_min; + min_index = index; + } + } + } + min_index +} + +// Never returns a request for reinsertion +fn resolve_overflow_without_reinsertion(node: &mut ParentNode) -> InsertionResult +where + T: RTreeObject, + Params: RTreeParams, +{ + 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 +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); + InsertionResult::Reinsert(nodes_for_reinsertion, current_depth) + } else { + InsertionResult::Complete + } +} + +fn split(node: &mut ParentNode) -> RTreeNode +where + T: RTreeObject, + Params: RTreeParams, +{ + 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 mut best_index = min_size; + + for k in min_size..=node.children.len() - min_size { + let mut first_envelope = node.children[k - 1].envelope(); + let mut second_envelope = node.children[k].envelope(); + let (l, r) = node.children.split_at(k); + for child in l { + first_envelope.merge(&child.envelope()); + } + for child in r { + second_envelope.merge(&child.envelope()); + } + + let overlap_value = first_envelope.intersection_area(&second_envelope); + let area_value = first_envelope.area() + second_envelope.area(); + let new_best = (overlap_value, area_value); + if new_best < best || k == min_size { + best = new_best; + best_index = k; + } + } + let off_split = node.children.split_off(best_index); + node.envelope = envelope_for_children(&node.children); + RTreeNode::Parent(ParentNode::new_parent(off_split)) +} + +fn get_split_axis(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 until = node.children.len() - min_size + 1; + for axis in 0..::Point::DIMENSIONS { + // Sort children along the current axis + T::Envelope::sort_envelopes(axis, &mut node.children); + let mut first_envelope = T::Envelope::new_empty(); + let mut second_envelope = T::Envelope::new_empty(); + for child in &node.children[..min_size] { + first_envelope.merge(&child.envelope()); + } + for child in &node.children[until..] { + second_envelope.merge(&child.envelope()); + } + for k in min_size..until { + let mut first_modified = first_envelope.clone(); + let mut second_modified = second_envelope.clone(); + let (l, r) = node.children.split_at(k); + for child in l { + first_modified.merge(&child.envelope()); + } + for child in r { + second_modified.merge(&child.envelope()); + } + + let perimeter_value = + first_modified.perimeter_value() + second_modified.perimeter_value(); + if best_goodness > perimeter_value { + best_axis = axis; + best_goodness = perimeter_value; + } + } + } + best_axis +} + +fn get_nodes_for_reinsertion(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 + node.children.sort_unstable_by(|l, r| { + let l_center = l.envelope().center(); + let r_center = r.envelope().center(); + l_center + .sub(¢er) + .length_2() + .partial_cmp(&(r_center.sub(¢er)).length_2()) + .unwrap() + }); + let num_children = node.children.len(); + let result = node + .children + .split_off(num_children - Params::REINSERTION_COUNT); + node.envelope = envelope_for_children(&node.children); + result +} diff --git a/thirdparty/rstar/src/algorithm/selection_functions.rs b/thirdparty/rstar/src/algorithm/selection_functions.rs new file mode 100644 index 0000000..3df80ae --- /dev/null +++ b/thirdparty/rstar/src/algorithm/selection_functions.rs @@ -0,0 +1,241 @@ +use crate::envelope::Envelope; +use crate::object::PointDistance; +use crate::object::RTreeObject; +use crate::Point; + +/// Advanced trait to iterate through an r-tree. Usually it should not be required to be implemented. +/// +/// It is important to know some details about the inner structure of +/// r-trees to understand this trait. Any node in an r-tree is either a *leaf* (containing exactly one `T: RTreeObject`) or +/// a *parent* (containing multiple nodes). +/// The main benefit of r-trees lies in their ability to efficiently guide searches through +/// the tree. This is done by *pruning*: Knowing the envelopes of parent nodes +/// often allows the search to completely skip them and all contained children instead of having +/// to iterate through them, e.g. when searching for elements in a non-intersecting envelope. +/// This often reduces the expected time from `O(n)` to `O(log(n))`. +/// +/// This trait can be used to define searches through the r-tree by defining whether a node +/// should be further investigated ("unpacked") or pruned. +/// +/// Usually, the various `locate_[...]` methods of [`super::super::RTree`] should cover most +/// common searches. Otherwise, implementing `SelectionFunction` and using +/// [`crate::RTree::locate_with_selection_function`] +/// can be used to tailor a custom search. +pub trait SelectionFunction +where + T: RTreeObject, +{ + /// Return `true` if a parent node should be unpacked during a search. + /// + /// The parent node's envelope is given to guide the decision. + fn should_unpack_parent(&self, envelope: &T::Envelope) -> bool; + + /// Returns `true` if a given child node should be returned during a search. + /// The default implementation will always return `true`. + fn should_unpack_leaf(&self, _leaf: &T) -> bool { + true + } +} + +pub struct SelectInEnvelopeFunction +where + T: RTreeObject, +{ + envelope: T::Envelope, +} + +impl SelectInEnvelopeFunction +where + T: RTreeObject, +{ + pub fn new(envelope: T::Envelope) -> Self { + SelectInEnvelopeFunction { envelope } + } +} + +impl SelectionFunction for SelectInEnvelopeFunction +where + T: RTreeObject, +{ + fn should_unpack_parent(&self, parent_envelope: &T::Envelope) -> bool { + self.envelope.intersects(parent_envelope) + } + + fn should_unpack_leaf(&self, leaf: &T) -> bool { + self.envelope.contains_envelope(&leaf.envelope()) + } +} + +pub struct SelectInEnvelopeFuncIntersecting +where + T: RTreeObject, +{ + envelope: T::Envelope, +} + +impl SelectInEnvelopeFuncIntersecting +where + T: RTreeObject, +{ + pub fn new(envelope: T::Envelope) -> Self { + SelectInEnvelopeFuncIntersecting { envelope } + } +} + +impl SelectionFunction for SelectInEnvelopeFuncIntersecting +where + T: RTreeObject, +{ + fn should_unpack_parent(&self, envelope: &T::Envelope) -> bool { + self.envelope.intersects(envelope) + } + + fn should_unpack_leaf(&self, leaf: &T) -> bool { + leaf.envelope().intersects(&self.envelope) + } +} + +pub struct SelectAllFunc; + +impl SelectionFunction for SelectAllFunc +where + T: RTreeObject, +{ + fn should_unpack_parent(&self, _: &T::Envelope) -> bool { + true + } +} + +/// A [trait.SelectionFunction] that only selects elements whose envelope +/// contains a specific point. +pub struct SelectAtPointFunction +where + T: RTreeObject, +{ + point: ::Point, +} + +impl SelectAtPointFunction +where + T: PointDistance, +{ + pub fn new(point: ::Point) -> Self { + SelectAtPointFunction { point } + } +} + +impl SelectionFunction for SelectAtPointFunction +where + T: PointDistance, +{ + fn should_unpack_parent(&self, envelope: &T::Envelope) -> bool { + envelope.contains_point(&self.point) + } + + fn should_unpack_leaf(&self, leaf: &T) -> bool { + leaf.contains_point(&self.point) + } +} + +/// A selection function that only chooses elements equal (`==`) to a +/// given element +pub struct SelectEqualsFunction<'a, T> +where + T: RTreeObject + PartialEq + 'a, +{ + /// Only elements equal to this object will be removed. + object_to_remove: &'a T, +} + +impl<'a, T> SelectEqualsFunction<'a, T> +where + T: RTreeObject + PartialEq, +{ + pub fn new(object_to_remove: &'a T) -> Self { + SelectEqualsFunction { object_to_remove } + } +} + +impl<'a, T> SelectionFunction for SelectEqualsFunction<'a, T> +where + T: RTreeObject + PartialEq, +{ + fn should_unpack_parent(&self, parent_envelope: &T::Envelope) -> bool { + parent_envelope.contains_envelope(&self.object_to_remove.envelope()) + } + + fn should_unpack_leaf(&self, leaf: &T) -> bool { + leaf == self.object_to_remove + } +} + +pub struct SelectWithinDistanceFunction +where + T: RTreeObject + PointDistance, +{ + circle_origin: ::Point, + squared_max_distance: <::Point as Point>::Scalar, +} + +impl SelectWithinDistanceFunction +where + T: RTreeObject + PointDistance, +{ + pub fn new( + circle_origin: ::Point, + squared_max_distance: <::Point as Point>::Scalar, + ) -> Self { + SelectWithinDistanceFunction { + circle_origin, + squared_max_distance, + } + } +} + +impl SelectionFunction for SelectWithinDistanceFunction +where + T: RTreeObject + PointDistance, +{ + fn should_unpack_parent(&self, parent_envelope: &T::Envelope) -> bool { + let envelope_distance = parent_envelope.distance_2(&self.circle_origin); + envelope_distance <= self.squared_max_distance + } + + fn should_unpack_leaf(&self, leaf: &T) -> bool { + leaf.distance_2_if_less_or_equal(&self.circle_origin, self.squared_max_distance) + .is_some() + } +} + +pub struct SelectByAddressFunction +where + T: RTreeObject, +{ + envelope: T::Envelope, + element_address: *const T, +} + +impl SelectByAddressFunction +where + T: RTreeObject, +{ + pub fn new(envelope: T::Envelope, element_address: &T) -> Self { + Self { + envelope, + element_address, + } + } +} + +impl SelectionFunction for SelectByAddressFunction +where + T: RTreeObject, +{ + fn should_unpack_parent(&self, parent_envelope: &T::Envelope) -> bool { + parent_envelope.contains_envelope(&self.envelope) + } + + fn should_unpack_leaf(&self, leaf: &T) -> bool { + core::ptr::eq(self.element_address, leaf) + } +} diff --git a/thirdparty/rstar/src/envelope.rs b/thirdparty/rstar/src/envelope.rs new file mode 100644 index 0000000..547194c --- /dev/null +++ b/thirdparty/rstar/src/envelope.rs @@ -0,0 +1,72 @@ +use crate::{Point, RTreeObject}; + +/// An envelope type that encompasses some child nodes. +/// +/// An envelope defines how different bounding boxes of inserted children in an r-tree can interact, +/// e.g. how they can be merged or intersected. +/// This trait is not meant to be implemented by the user. Currently, only one implementation +/// exists ([crate::AABB]) and should be used. +pub trait Envelope: Clone + PartialEq + ::core::fmt::Debug { + /// The envelope's point type. + type Point: Point; + + /// Creates a new, empty envelope that does not encompass any child. + fn new_empty() -> Self; + + /// Returns true if a point is contained within this envelope. + fn contains_point(&self, point: &Self::Point) -> bool; + + /// Returns true if another envelope is _fully contained_ within `self`. + fn contains_envelope(&self, aabb: &Self) -> bool; + + /// Extends `self` to contain another envelope. + fn merge(&mut self, other: &Self); + /// Returns the minimal envelope containing `self` and another envelope. + fn merged(&self, other: &Self) -> Self; + + /// Returns true if `self` and `other` intersect. The intersection might be + /// of zero area (the two envelopes only touching each other). + fn intersects(&self, other: &Self) -> bool; + /// Returns the area of the intersection of `self` and another envelope. + fn intersection_area(&self, other: &Self) -> ::Scalar; + + /// Returns this envelope's area. Must be at least 0. + fn area(&self) -> ::Scalar; + + /// Returns the squared distance between the envelope's border and a point. + /// + /// # Notes + /// - While euclidean distance will be the correct choice for most use cases, any distance metric + /// fulfilling the [usual axioms](https://en.wikipedia.org/wiki/Metric_space) + /// can be used when implementing this method + /// - Implementers **must** ensure that the distance metric used matches that of [crate::PointDistance::distance_2] + fn distance_2(&self, point: &Self::Point) -> ::Scalar; + + /// Returns the squared min-max distance, a concept that helps to find nearest neighbors efficiently. + /// + /// Visually, if an AABB and a point are given, the min-max distance returns the distance at which we + /// can be assured that an element must be present. This serves as an upper bound during nearest neighbor search. + /// + /// # References + /// [Roussopoulos, Nick, Stephen Kelley, and Frédéric Vincent. "Nearest neighbor queries." ACM sigmod record. Vol. 24. No. 2. ACM, 1995.](https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.133.2288) + fn min_max_dist_2(&self, point: &Self::Point) -> ::Scalar; + + /// Returns the envelope's center point. + fn center(&self) -> Self::Point; + + /// Returns a value proportional to the envelope's perimeter. + fn perimeter_value(&self) -> ::Scalar; + + /// Sorts a given set of objects with envelopes along one of their axes. + fn sort_envelopes>(axis: usize, envelopes: &mut [T]); + + /// Partitions objects with an envelope along a certain axis. + /// + /// After calling this, envelopes[0..selection_size] are all smaller + /// than envelopes[selection_size + 1..]. + fn partition_envelopes>( + axis: usize, + envelopes: &mut [T], + selection_size: usize, + ); +} diff --git a/thirdparty/rstar/src/lib.rs b/thirdparty/rstar/src/lib.rs new file mode 100644 index 0000000..5fd7131 --- /dev/null +++ b/thirdparty/rstar/src/lib.rs @@ -0,0 +1,64 @@ +//! An n-dimensional [r*-tree](https://en.wikipedia.org/wiki/R*-tree) implementation for use as a spatial index. +//! +//! This crate implements a flexible, n-dimensional r-tree implementation with +//! the r* (r star) insertion strategy. +//! +//! # R-Tree +//! An r-tree is a data structure containing _spatial data_, optimized for +//! nearest neighbor search. +//! _Spatial data_ refers to an object that has the notion of a position and extent: +//! for example points, lines and rectangles in any dimension. +//! +//! +//! # Further documentation +//! The crate's main data structure and documentation is the [RTree] struct. +//! +//! ## Primitives +//! The pre-defined primitives like lines and rectangles contained in +//! the [primitives module](crate::primitives) may be of interest for a quick start. +//! ## `Geo` +//! For use with the wider Georust ecosystem, the primitives in the [`geo`](https://docs.rs/geo/latest/geo/#types) crate +//! can also be used. +//! +//! # (De)Serialization +//! Enable the `serde` feature for [serde](https://crates.io/crates/serde) support. +//! +//! # Mint compatibility with other crates +//! Enable the `mint` feature for +//! [`mint`](https://crates.io/crates/mint) support. See the +//! documentation on the [mint] module for an expample of an +//! integration with the +//! [`nalgebra`](https://crates.io/crates/nalgebra) crate. +#![deny(missing_docs)] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), no_std)] + +extern crate alloc; + +mod aabb; +mod algorithm; +mod envelope; +mod node; +mod object; +mod params; +mod point; +pub mod primitives; +mod rtree; + +#[cfg(feature = "mint")] +pub mod mint; + +#[cfg(test)] +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::point::{Point, RTreeNum}; +pub use crate::rtree::RTree; + +pub use crate::algorithm::iterators; diff --git a/thirdparty/rstar/src/mint.rs b/thirdparty/rstar/src/mint.rs new file mode 100644 index 0000000..7d64266 --- /dev/null +++ b/thirdparty/rstar/src/mint.rs @@ -0,0 +1,94 @@ +//! [`mint`](https://crates.io/crates/mint) is a library for +//! interoperability between maths crates, for example, you may want +//! to use [nalgebra](https://crates.io/crates/nalgebra) types for +//! representing your points and _also_ use the same points with the +//! `rstar` library. +//! +//! Here is an example of how you might do that using `mint` types for +//! compatibility between the two libraries. Make sure to enable the +//! `mint` features on both the `nalgebra` and the `rstar` crates for +//! this to work. You will also need to depend on the +//! [`mint`](https://crates.io/crates/mint) crate. +//! +//! ``` +//! use rstar::RTree; +//! +//! let point1 = nalgebra::Point2::new(0.0, 0.0); +//! let point2 = nalgebra::Point2::new(1.0, 1.0); +//! +//! // First we have to convert the foreign points into the mint +//! // compatibility types before we can store them in the rtree +//! +//! let mint_point1: mint::Point2 = point1.into(); +//! let mint_point2: mint::Point2 = point2.into(); +//! +//! // Now we can use them with rtree structs and methods +//! let mut rtree = RTree::new(); +//! +//! rtree.insert(mint_point2); +//! +//! assert_eq!(rtree.nearest_neighbor(&mint_point1), Some(&mint_point2)); +//! ``` + +use crate::{Point, RTreeNum}; + +impl Point for mint::Point2 { + type Scalar = T; + + const DIMENSIONS: usize = 2; + + fn generate(mut generator: impl FnMut(usize) -> Self::Scalar) -> Self { + mint::Point2 { + x: generator(0), + y: generator(1), + } + } + + fn nth(&self, index: usize) -> Self::Scalar { + match index { + 0 => self.x, + 1 => self.y, + _ => unreachable!(), + } + } + + fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar { + match index { + 0 => &mut self.x, + 1 => &mut self.y, + _ => unreachable!(), + } + } +} + +impl Point for mint::Point3 { + type Scalar = T; + + const DIMENSIONS: usize = 3; + + fn generate(mut generator: impl FnMut(usize) -> Self::Scalar) -> Self { + mint::Point3 { + x: generator(0), + y: generator(1), + z: generator(2), + } + } + + fn nth(&self, index: usize) -> Self::Scalar { + match index { + 0 => self.x, + 1 => self.y, + 2 => self.z, + _ => unreachable!(), + } + } + + fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar { + match index { + 0 => &mut self.x, + 1 => &mut self.y, + 2 => &mut self.z, + _ => unreachable!(), + } + } +} diff --git a/thirdparty/rstar/src/node.rs b/thirdparty/rstar/src/node.rs new file mode 100644 index 0000000..f455752 --- /dev/null +++ b/thirdparty/rstar/src/node.rs @@ -0,0 +1,168 @@ +use crate::envelope::Envelope; +use crate::object::RTreeObject; +use crate::params::RTreeParams; + +#[cfg(not(test))] +use alloc::vec::Vec; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr( + feature = "serde", + serde(bound( + serialize = "T: Serialize, T::Envelope: Serialize", + deserialize = "T: Deserialize<'de>, T::Envelope: Deserialize<'de>" + )) +)] + +/// An internal tree node. +/// +/// For most applications, using this type should not be required. +pub enum RTreeNode +where + T: RTreeObject, +{ + /// A leaf node, only containing the r-tree object + Leaf(T), + /// A parent node containing several child nodes + Parent(ParentNode), +} + +/// Represents an internal parent node. +/// +/// For most applications, using this type should not be required. Allows read access to this +/// node's envelope and its children. +#[derive(Debug, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct ParentNode +where + T: RTreeObject, +{ + pub(crate) children: Vec>, + pub(crate) envelope: T::Envelope, +} + +impl RTreeObject for RTreeNode +where + T: RTreeObject, +{ + type Envelope = T::Envelope; + + fn envelope(&self) -> Self::Envelope { + match self { + RTreeNode::Leaf(ref t) => t.envelope(), + RTreeNode::Parent(ref data) => data.envelope.clone(), + } + } +} + +#[doc(hidden)] +impl RTreeNode +where + T: RTreeObject, +{ + pub fn is_leaf(&self) -> bool { + match self { + RTreeNode::Leaf(..) => true, + RTreeNode::Parent(..) => false, + } + } +} + +impl ParentNode +where + T: RTreeObject, +{ + /// Returns this node's children + pub fn children(&self) -> &[RTreeNode] { + &self.children + } + + /// Returns the smallest envelope that encompasses all children. + pub fn envelope(&self) -> T::Envelope { + self.envelope.clone() + } + + pub(crate) fn new_root() -> Self + where + Params: RTreeParams, + { + ParentNode { + envelope: Envelope::new_empty(), + children: Vec::with_capacity(Params::MAX_SIZE + 1), + } + } + + pub(crate) fn new_parent(children: Vec>) -> Self { + let envelope = envelope_for_children(&children); + + ParentNode { envelope, children } + } + + #[cfg(test)] + #[allow(missing_docs)] + pub fn sanity_check(&self, check_max_size: bool) -> Option + where + Params: RTreeParams, + { + if self.children.is_empty() { + Some(0) + } else { + let mut result = None; + self.sanity_check_inner::(check_max_size, 1, &mut result); + result + } + } + + #[cfg(test)] + fn sanity_check_inner( + &self, + check_max_size: bool, + height: usize, + leaf_height: &mut Option, + ) where + Params: RTreeParams, + { + if height > 1 { + 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; + assert!(self.children.len() <= max_size); + } + + for child in &self.children { + match child { + RTreeNode::Leaf(ref t) => { + envelope.merge(&t.envelope()); + if let Some(ref leaf_height) = leaf_height { + assert_eq!(height, *leaf_height); + } else { + *leaf_height = Some(height); + } + } + RTreeNode::Parent(ref data) => { + envelope.merge(&data.envelope); + data.sanity_check_inner::(check_max_size, height + 1, leaf_height); + } + } + } + assert_eq!(self.envelope, envelope); + } +} + +pub fn envelope_for_children(children: &[RTreeNode]) -> T::Envelope +where + T: RTreeObject, +{ + let mut result = T::Envelope::new_empty(); + for child in children { + result.merge(&child.envelope()); + } + result +} diff --git a/thirdparty/rstar/src/object.rs b/thirdparty/rstar/src/object.rs new file mode 100644 index 0000000..f388b51 --- /dev/null +++ b/thirdparty/rstar/src/object.rs @@ -0,0 +1,233 @@ +use crate::aabb::AABB; +use crate::envelope::Envelope; +use crate::point::{Point, PointExt}; + +/// An object that can be inserted into an r-tree. +/// +/// This trait must be implemented for any object to be inserted into an r-tree. +/// Some simple objects that already implement this trait can be found in the +/// [crate::primitives] module. +/// +/// The only property required of such an object is its [crate::Envelope]. +/// Most simply, this method should return the [axis aligned bounding box](AABB) +/// of the object. Other envelope types may be supported in the future. +/// +/// *Note*: It is a logic error if an object's envelope changes after insertion into +/// an r-tree. +/// +/// # Type parameters +/// `Envelope`: The object's envelope type. At the moment, only [AABB] is +/// available. +/// +/// # Example implementation +/// ``` +/// use rstar::{RTreeObject, AABB}; +/// +/// struct Player +/// { +/// name: String, +/// x_coordinate: f64, +/// y_coordinate: f64 +/// } +/// +/// impl RTreeObject for Player +/// { +/// type Envelope = AABB<[f64; 2]>; +/// +/// fn envelope(&self) -> Self::Envelope +/// { +/// AABB::from_point([self.x_coordinate, self.y_coordinate]) +/// } +/// } +/// +/// use rstar::RTree; +/// +/// let mut tree = RTree::new(); +/// +/// // Insert a few players... +/// tree.insert(Player { +/// name: "Forlorn Freeman".into(), +/// x_coordinate: 1., +/// y_coordinate: 0. +/// }); +/// tree.insert(Player { +/// name: "Sarah Croft".into(), +/// x_coordinate: 0.5, +/// y_coordinate: 0.5, +/// }); +/// tree.insert(Player { +/// name: "Geralt of Trivia".into(), +/// x_coordinate: 0., +/// y_coordinate: 2., +/// }); +/// +/// // Now we are ready to ask some questions! +/// let envelope = AABB::from_point([0.5, 0.5]); +/// let likely_sarah_croft = tree.locate_in_envelope(&envelope).next(); +/// println!("Found {:?} lurking around at (0.5, 0.5)!", likely_sarah_croft.unwrap().name); +/// # assert!(likely_sarah_croft.is_some()); +/// +/// let unit_square = AABB::from_corners([-1.0, -1.0], [1., 1.]); +/// for player in tree.locate_in_envelope(&unit_square) { +/// println!("And here is {:?} spelunking in the unit square.", player.name); +/// } +/// # assert_eq!(tree.locate_in_envelope(&unit_square).count(), 2); +/// ``` +pub trait RTreeObject { + /// The object's envelope type. Usually, [AABB] will be the right choice. + /// This type also defines the object's dimensionality. + type Envelope: Envelope; + + /// Returns the object's envelope. + /// + /// Usually, this will return the object's [axis aligned bounding box](AABB). + fn envelope(&self) -> Self::Envelope; +} + +/// Defines objects which can calculate their minimal distance to a point. +/// +/// This trait is most notably necessary for support of [nearest_neighbor](struct.RTree#method.nearest_neighbor) +/// queries. +/// +/// # Example +/// ``` +/// use rstar::{RTreeObject, PointDistance, AABB}; +/// +/// struct Circle +/// { +/// origin: [f32; 2], +/// radius: f32, +/// } +/// +/// impl RTreeObject for Circle { +/// type Envelope = AABB<[f32; 2]>; +/// +/// fn envelope(&self) -> Self::Envelope { +/// let corner_1 = [self.origin[0] - self.radius, self.origin[1] - self.radius]; +/// let corner_2 = [self.origin[0] + self.radius, self.origin[1] + self.radius]; +/// AABB::from_corners(corner_1, corner_2) +/// } +/// } +/// +/// impl PointDistance for Circle +/// { +/// fn distance_2(&self, point: &[f32; 2]) -> f32 +/// { +/// let d_x = self.origin[0] - point[0]; +/// let d_y = self.origin[1] - point[1]; +/// let distance_to_origin = (d_x * d_x + d_y * d_y).sqrt(); +/// let distance_to_ring = distance_to_origin - self.radius; +/// let distance_to_circle = f32::max(0.0, distance_to_ring); +/// // We must return the squared distance! +/// distance_to_circle * distance_to_circle +/// } +/// +/// // This implementation is not required but more efficient since it +/// // omits the calculation of a square root +/// fn contains_point(&self, point: &[f32; 2]) -> bool +/// { +/// let d_x = self.origin[0] - point[0]; +/// let d_y = self.origin[1] - point[1]; +/// let distance_to_origin_2 = (d_x * d_x + d_y * d_y); +/// let radius_2 = self.radius * self.radius; +/// distance_to_origin_2 <= radius_2 +/// } +/// } +/// +/// +/// let circle = Circle { +/// origin: [1.0, 0.0], +/// radius: 1.0, +/// }; +/// +/// assert_eq!(circle.distance_2(&[-1.0, 0.0]), 1.0); +/// assert_eq!(circle.distance_2(&[-2.0, 0.0]), 4.0); +/// assert!(circle.contains_point(&[1.0, 0.0])); +/// ``` +pub trait PointDistance: RTreeObject { + /// Returns the squared distance between an object and a point. + /// + /// # Notes + /// - While euclidean distance will be the correct choice for most use cases, any distance metric + /// fulfilling the [usual axioms](https://en.wikipedia.org/wiki/Metric_space) + /// can be used when implementing this method + /// - Implementers **must** ensure that the distance metric used matches that of [crate::Envelope::distance_2] + fn distance_2( + &self, + point: &::Point, + ) -> <::Point as Point>::Scalar; + + /// Returns `true` if a point is contained within this object. + /// + /// By default, any point returning a `distance_2` less than or equal to zero is considered to be + /// contained within `self`. Changing this default behavior is advised if calculating the squared distance + /// is more computationally expensive than a point containment check. + fn contains_point(&self, point: &::Point) -> bool { + self.distance_2(point) <= num_traits::zero() + } + + /// Returns the squared distance to this object, or `None` if the distance + /// is larger than a given maximum value. + /// + /// Some algorithms only need to know an object's distance + /// if it is less than or equal to a maximum value. In these cases, it may be + /// faster to calculate a lower bound of the distance first and returning + /// early if the object cannot be closer than the given maximum. + /// + /// The provided default implementation will use the distance to the object's + /// envelope as a lower bound. + /// + /// If performance is critical and the object's distance calculation is fast, + /// it may be beneficial to overwrite this implementation. + fn distance_2_if_less_or_equal( + &self, + point: &::Point, + max_distance_2: <::Point as Point>::Scalar, + ) -> Option<<::Point as Point>::Scalar> { + let envelope_distance = self.envelope().distance_2(point); + if envelope_distance <= max_distance_2 { + let distance_2 = self.distance_2(point); + if distance_2 <= max_distance_2 { + return Some(distance_2); + } + } + None + } +} + +impl

RTreeObject for P +where + P: Point, +{ + type Envelope = AABB

; + + fn envelope(&self) -> AABB

{ + AABB::from_point(self.clone()) + } +} + +impl

PointDistance for P +where + P: Point, +{ + fn distance_2(&self, point: &P) -> P::Scalar { + ::distance_2(self, point) + } + + fn contains_point(&self, point: &::Point) -> bool { + self == point + } + + fn distance_2_if_less_or_equal( + &self, + point: &::Point, + max_distance_2: <::Point as Point>::Scalar, + ) -> Option { + let distance_2 = ::distance_2(self, point); + if distance_2 <= max_distance_2 { + Some(distance_2) + } else { + None + } + } +} diff --git a/thirdparty/rstar/src/params.rs b/thirdparty/rstar/src/params.rs new file mode 100644 index 0000000..03c2777 --- /dev/null +++ b/thirdparty/rstar/src/params.rs @@ -0,0 +1,116 @@ +use crate::algorithm::rstar::RStarInsertionStrategy; +use crate::{Envelope, Point, RTree, RTreeObject}; + +/// Defines static parameters for an r-tree. +/// +/// Internally, an r-tree contains several nodes, similar to a b-tree. These parameters change +/// the size of these nodes and can be used to fine-tune the tree's performance. +/// +/// # Example +/// ``` +/// use rstar::{RTreeParams, RTree, RStarInsertionStrategy}; +/// +/// // 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(); +/// // 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); +/// # } +/// ``` +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; + + /// The insertion strategy which is used when calling [RTree::insert]. + type DefaultInsertionStrategy: InsertionStrategy; +} + +/// The default parameters used when creating an r-tree without specific parameters. +#[derive(Clone, Copy, PartialEq, Eq, Default)] +pub struct DefaultParams; + +impl RTreeParams for DefaultParams { + const MIN_SIZE: usize = 3; + const MAX_SIZE: usize = 6; + const REINSERTION_COUNT: usize = 2; + type DefaultInsertionStrategy = RStarInsertionStrategy; +} + +/// 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; +} + +pub fn verify_parameters() { + assert!( + P::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 + ); + + 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 dimension = ::Point::DIMENSIONS; + assert!( + dimension > 1, + "Point dimension too small - must be at least 2" + ); +} diff --git a/thirdparty/rstar/src/point.rs b/thirdparty/rstar/src/point.rs new file mode 100644 index 0000000..a6839dd --- /dev/null +++ b/thirdparty/rstar/src/point.rs @@ -0,0 +1,437 @@ +use core::fmt::Debug; +use num_traits::{Bounded, Num, Signed, Zero}; + +/// Defines a number type that is compatible with rstar. +/// +/// rstar works out of the box with the following standard library types: +/// - i8, i16, i32, i64, i128, isize +/// - [Wrapping](core::num::Wrapping) versions of the above +/// - f32, f64 +/// +/// This type cannot be implemented directly. Instead, it is required to implement +/// all required traits from the `num_traits` crate. +/// +/// # Example +/// ``` +/// # extern crate num_traits; +/// use num_traits::{Bounded, Num, Signed}; +/// +/// #[derive(Clone, Copy, PartialEq, PartialOrd, Debug)] +/// struct MyFancyNumberType(f32); +/// +/// impl num_traits::Bounded for MyFancyNumberType { +/// // ... details hidden ... +/// # fn min_value() -> Self { Self(Bounded::min_value()) } +/// # +/// # fn max_value() -> Self { Self(Bounded::max_value()) } +/// } +/// +/// impl Signed for MyFancyNumberType { +/// // ... details hidden ... +/// # fn abs(&self) -> Self { unimplemented!() } +/// # +/// # fn abs_sub(&self, other: &Self) -> Self { unimplemented!() } +/// # +/// # fn signum(&self) -> Self { unimplemented!() } +/// # +/// # fn is_positive(&self) -> bool { unimplemented!() } +/// # +/// # fn is_negative(&self) -> bool { unimplemented!() } +/// } +/// +/// impl Num for MyFancyNumberType { +/// // ... details hidden ... +/// # type FromStrRadixErr = num_traits::ParseFloatError; +/// # fn from_str_radix(str: &str, radix: u32) -> Result { unimplemented!() } +/// } +/// +/// // Lots of traits are still missing to make the above code compile, but +/// // let's assume they're implemented. `MyFancyNumberType` type now readily implements +/// // RTreeNum and can be used with r-trees: +/// # fn main() { +/// use rstar::RTree; +/// let mut rtree = RTree::new(); +/// rtree.insert([MyFancyNumberType(0.0), MyFancyNumberType(0.0)]); +/// # } +/// +/// # impl num_traits::Zero for MyFancyNumberType { +/// # fn zero() -> Self { unimplemented!() } +/// # fn is_zero(&self) -> bool { unimplemented!() } +/// # } +/// # +/// # impl num_traits::One for MyFancyNumberType { +/// # fn one() -> Self { unimplemented!() } +/// # } +/// # +/// # impl core::ops::Mul for MyFancyNumberType { +/// # type Output = Self; +/// # fn mul(self, rhs: Self) -> Self { unimplemented!() } +/// # } +/// # +/// # impl core::ops::Add for MyFancyNumberType { +/// # type Output = Self; +/// # fn add(self, rhs: Self) -> Self { unimplemented!() } +/// # } +/// # +/// # impl core::ops::Sub for MyFancyNumberType { +/// # type Output = Self; +/// # fn sub(self, rhs: Self) -> Self { unimplemented!() } +/// # } +/// # +/// # impl core::ops::Div for MyFancyNumberType { +/// # type Output = Self; +/// # fn div(self, rhs: Self) -> Self { unimplemented!() } +/// # } +/// # +/// # impl core::ops::Rem for MyFancyNumberType { +/// # type Output = Self; +/// # fn rem(self, rhs: Self) -> Self { unimplemented!() } +/// # } +/// # +/// # impl core::ops::Neg for MyFancyNumberType { +/// # type Output = Self; +/// # fn neg(self) -> Self { unimplemented!() } +/// # } +/// # +/// ``` +/// +pub trait RTreeNum: Bounded + Num + Clone + Copy + Signed + PartialOrd + Debug {} + +impl RTreeNum for S where S: Bounded + Num + Clone + Copy + Signed + PartialOrd + Debug {} + +/// Defines a point type that is compatible with rstar. +/// +/// This trait should be used for interoperability with other point types, not to define custom objects +/// that can be inserted into r-trees. Use [`crate::RTreeObject`] or +/// [`crate::primitives::GeomWithData`] instead. +/// This trait defines points, not points with metadata. +/// +/// `Point` is implemented out of the box for arrays like `[f32; 2]` or `[f64; 7]` (for any number of dimensions), +/// and for tuples like `(int, int)` and `(f64, f64, f64)` so tuples with only elements of the same type (up to dimension 9). +/// +/// +/// # Implementation example +/// Supporting a custom point type might look like this: +/// +/// ``` +/// use rstar::Point; +/// +/// #[derive(Copy, Clone, PartialEq, Debug)] +/// struct IntegerPoint +/// { +/// x: i32, +/// y: i32 +/// } +/// +/// impl Point for IntegerPoint +/// { +/// type Scalar = i32; +/// const DIMENSIONS: usize = 2; +/// +/// fn generate(mut generator: impl FnMut(usize) -> Self::Scalar) -> Self +/// { +/// IntegerPoint { +/// x: generator(0), +/// y: generator(1) +/// } +/// } +/// +/// fn nth(&self, index: usize) -> Self::Scalar +/// { +/// match index { +/// 0 => self.x, +/// 1 => self.y, +/// _ => unreachable!() +/// } +/// } +/// +/// fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar +/// { +/// match index { +/// 0 => &mut self.x, +/// 1 => &mut self.y, +/// _ => unreachable!() +/// } +/// } +/// } +/// ``` +pub trait Point: Clone + PartialEq + Debug { + /// The number type used by this point type. + type Scalar: RTreeNum; + + /// The number of dimensions of this point type. + const DIMENSIONS: usize; + + /// Creates a new point value with given values for each dimension. + /// + /// The value that each dimension should be initialized with is given by the parameter `generator`. + /// Calling `generator(n)` returns the value of dimension `n`, `n` will be in the range `0 .. Self::DIMENSIONS`, + /// and will be called with values of `n` in ascending order. + fn generate(generator: impl FnMut(usize) -> Self::Scalar) -> Self; + + /// Returns a single coordinate of this point. + /// + /// Returns the coordinate indicated by `index`. `index` is always smaller than `Self::DIMENSIONS`. + fn nth(&self, index: usize) -> Self::Scalar; + + /// Mutable variant of [nth](#methods.nth). + fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar; +} + +impl PointExt for T where T: Point {} + +/// Utility functions for Point +pub trait PointExt: Point { + /// Returns a new Point with all components set to zero. + fn new() -> Self { + Self::from_value(Zero::zero()) + } + + /// Applies `f` to each pair of components of `self` and `other`. + fn component_wise( + &self, + other: &Self, + mut f: impl FnMut(Self::Scalar, Self::Scalar) -> Self::Scalar, + ) -> Self { + Self::generate(|i| f(self.nth(i), other.nth(i))) + } + + /// Returns whether all pairs of components of `self` and `other` pass test closure `f`. Short circuits if any result is false. + fn all_component_wise( + &self, + other: &Self, + mut f: impl FnMut(Self::Scalar, Self::Scalar) -> bool, + ) -> bool { + (0..Self::DIMENSIONS).all(|i| f(self.nth(i), other.nth(i))) + } + + /// Returns the dot product of `self` and `rhs`. + fn dot(&self, rhs: &Self) -> Self::Scalar { + self.component_wise(rhs, |l, r| l * r) + .fold(Zero::zero(), |acc, val| acc + val) + } + + /// Folds (aka reduces or injects) the Point component wise using `f` and returns the result. + /// fold() takes two arguments: an initial value, and a closure with two arguments: an 'accumulator', and the value of the current component. + /// The closure returns the value that the accumulator should have for the next iteration. + /// + /// The `start_value` is the value the accumulator will have on the first call of the closure. + /// + /// After applying the closure to every component of the Point, fold() returns the accumulator. + fn fold(&self, start_value: T, mut f: impl FnMut(T, Self::Scalar) -> T) -> T { + (0..Self::DIMENSIONS).fold(start_value, |accumulated, i| f(accumulated, self.nth(i))) + } + + /// Returns a Point with every component set to `value`. + fn from_value(value: Self::Scalar) -> Self { + Self::generate(|_| value) + } + + /// Returns a Point with each component set to the smallest of each component pair of `self` and `other`. + fn min_point(&self, other: &Self) -> Self { + self.component_wise(other, min_inline) + } + + /// Returns a Point with each component set to the biggest of each component pair of `self` and `other`. + fn max_point(&self, other: &Self) -> Self { + self.component_wise(other, max_inline) + } + + /// Returns the squared length of this Point as if it was a vector. + fn length_2(&self) -> Self::Scalar { + self.fold(Zero::zero(), |acc, cur| cur * cur + acc) + } + + /// Substracts `other` from `self` component wise. + fn sub(&self, other: &Self) -> Self { + self.component_wise(other, |l, r| l - r) + } + + /// Adds `other` to `self` component wise. + fn add(&self, other: &Self) -> Self { + self.component_wise(other, |l, r| l + r) + } + + /// Multiplies `self` with `scalar` component wise. + fn mul(&self, scalar: Self::Scalar) -> Self { + self.map(|coordinate| coordinate * scalar) + } + + /// Applies `f` to `self` component wise. + fn map(&self, mut f: impl FnMut(Self::Scalar) -> Self::Scalar) -> Self { + Self::generate(|i| f(self.nth(i))) + } + + /// Returns the squared distance between `self` and `other`. + fn distance_2(&self, other: &Self) -> Self::Scalar { + self.sub(other).length_2() + } +} + +#[inline] +pub fn min_inline(a: S, b: S) -> S +where + S: RTreeNum, +{ + if a < b { + a + } else { + b + } +} + +#[inline] +pub fn max_inline(a: S, b: S) -> S +where + S: RTreeNum, +{ + if a > b { + a + } else { + b + } +} + +impl Point for [S; N] +where + S: RTreeNum, +{ + type Scalar = S; + + const DIMENSIONS: usize = N; + + fn generate(mut generator: impl FnMut(usize) -> S) -> Self { + // The same implementation used in std::array::from_fn + // Since this is a const generic it gets unrolled + let mut idx = 0; + [(); N].map(|_| { + let res = generator(idx); + idx += 1; + res + }) + } + + #[inline] + fn nth(&self, index: usize) -> Self::Scalar { + self[index] + } + + #[inline] + fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar { + &mut self[index] + } +} + +macro_rules! count_exprs { + () => (0); + ($head:expr) => (1); + ($head:expr, $($tail:expr),*) => (1 + count_exprs!($($tail),*)); +} + +macro_rules! fixed_type { + ($expr:expr, $type:ty) => { + $type + }; +} + +macro_rules! impl_point_for_tuple { + ($($index:expr => $name:ident),+) => { + impl Point for ($(fixed_type!($index, S),)+) + where + S: RTreeNum + { + type Scalar = S; + + const DIMENSIONS: usize = count_exprs!($($index),*); + + fn generate(mut generator: impl FnMut(usize) -> S) -> Self { + ($(generator($index),)+) + } + + #[inline] + fn nth(&self, index: usize) -> Self::Scalar { + let ($($name,)+) = self; + + match index { + $($index => *$name,)+ + _ => unreachable!("index {} out of bounds for tuple", index), + } + } + + #[inline] + fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar { + let ($($name,)+) = self; + + match index { + $($index => $name,)+ + _ => unreachable!("index {} out of bounds for tuple", index), + } + } + } + }; +} + +impl_point_for_tuple!(0 => a); +impl_point_for_tuple!(0 => a, 1 => b); +impl_point_for_tuple!(0 => a, 1 => b, 2 => c); +impl_point_for_tuple!(0 => a, 1 => b, 2 => c, 3 => d); +impl_point_for_tuple!(0 => a, 1 => b, 2 => c, 3 => d, 4 => e); +impl_point_for_tuple!(0 => a, 1 => b, 2 => c, 3 => d, 4 => e, 5 => f); +impl_point_for_tuple!(0 => a, 1 => b, 2 => c, 3 => d, 4 => e, 5 => f, 6 => g); +impl_point_for_tuple!(0 => a, 1 => b, 2 => c, 3 => d, 4 => e, 5 => f, 6 => g, 7 => h); +impl_point_for_tuple!(0 => a, 1 => b, 2 => c, 3 => d, 4 => e, 5 => f, 6 => g, 7 => h, 8 => i); +impl_point_for_tuple!(0 => a, 1 => b, 2 => c, 3 => d, 4 => e, 5 => f, 6 => g, 7 => h, 8 => i, 9 => j); + +#[cfg(test)] +mod tests { + use super::*; + use core::num::Wrapping; + + #[test] + fn test_types() { + fn assert_impl_rtreenum() {} + + assert_impl_rtreenum::(); + assert_impl_rtreenum::(); + assert_impl_rtreenum::(); + assert_impl_rtreenum::(); + assert_impl_rtreenum::(); + assert_impl_rtreenum::(); + assert_impl_rtreenum::>(); + assert_impl_rtreenum::>(); + assert_impl_rtreenum::>(); + assert_impl_rtreenum::>(); + assert_impl_rtreenum::>(); + assert_impl_rtreenum::>(); + assert_impl_rtreenum::(); + assert_impl_rtreenum::(); + } + + macro_rules! test_tuple_configuration { + ($($index:expr),*) => { + let a = ($($index),*); + $(assert_eq!(a.nth($index), $index));* + } + } + + #[test] + fn test_tuples() { + // Test a couple of simple cases + let simple_int = (0, 1, 2); + assert_eq!(simple_int.nth(2), 2); + let simple_float = (0.5, 0.67, 1234.56); + assert_eq!(simple_float.nth(2), 1234.56); + let long_int = (0, 1, 2, 3, 4, 5, 6, 7, 8); + assert_eq!(long_int.nth(8), 8); + + // Generate the code to test every nth function for every Tuple length + test_tuple_configuration!(0, 1); + test_tuple_configuration!(0, 1, 2); + test_tuple_configuration!(0, 1, 2, 3); + test_tuple_configuration!(0, 1, 2, 3, 4); + test_tuple_configuration!(0, 1, 2, 3, 4, 5); + test_tuple_configuration!(0, 1, 2, 3, 4, 5, 6); + test_tuple_configuration!(0, 1, 2, 3, 4, 5, 6, 7); + test_tuple_configuration!(0, 1, 2, 3, 4, 5, 6, 7, 8); + } +} diff --git a/thirdparty/rstar/src/primitives/cached_envelope.rs b/thirdparty/rstar/src/primitives/cached_envelope.rs new file mode 100644 index 0000000..ae040f3 --- /dev/null +++ b/thirdparty/rstar/src/primitives/cached_envelope.rs @@ -0,0 +1,127 @@ +use crate::envelope::Envelope; +use crate::object::PointDistance; +use crate::{object::RTreeObject, point::Point}; +use core::ops::Deref; + +/// An [RTreeObject] with an inner geometry whose envelope is cached to improve efficiency. +/// +/// For complex geometry like polygons, computing the envelope can become a bottleneck during +/// tree construction and querying. Hence this combinator computes it once during creation, +/// stores it and then returns a copy. +/// +/// **Note:** the container itself implements [RTreeObject] and inner geometry `T` can be +/// accessed via an implementation of `Deref`. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct CachedEnvelope { + inner: T, + cached_env: T::Envelope, +} + +impl RTreeObject for CachedEnvelope +where + T::Envelope: Clone, +{ + type Envelope = T::Envelope; + + fn envelope(&self) -> Self::Envelope { + self.cached_env.clone() + } +} + +impl PointDistance for CachedEnvelope { + fn distance_2( + &self, + point: &::Point, + ) -> <::Point as Point>::Scalar { + self.inner.distance_2(point) + } + + fn contains_point(&self, p: &::Point) -> bool { + self.inner.contains_point(p) + } + + fn distance_2_if_less_or_equal( + &self, + point: &::Point, + max_distance_2: <::Point as Point>::Scalar, + ) -> Option<<::Point as Point>::Scalar> { + self.inner + .distance_2_if_less_or_equal(point, max_distance_2) + } +} + +impl CachedEnvelope { + /// Create a new [CachedEnvelope] struct using the provided geometry. + pub fn new(inner: T) -> Self { + let cached_env = inner.envelope(); + + Self { inner, cached_env } + } +} + +impl Deref for CachedEnvelope { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +#[cfg(test)] +mod test { + use super::CachedEnvelope; + use crate::object::PointDistance; + use crate::primitives::GeomWithData; + + use approx::*; + + use crate::{primitives::Line, RTree}; + + #[test] + fn container_in_rtree() { + let line_1 = CachedEnvelope::new(Line::new([0.0, 0.0], [1.0, 1.0])); + let line_2 = CachedEnvelope::new(Line::new([0.0, 0.0], [-1.0, 1.0])); + let tree = RTree::bulk_load(vec![line_1, line_2]); + + assert!(tree.contains(&line_1)); + } + + #[test] + fn container_edge_distance() { + let edge = CachedEnvelope::new(Line::new([0.5, 0.5], [0.5, 2.0])); + + assert_abs_diff_eq!(edge.distance_2(&[0.5, 0.5]), 0.0); + assert_abs_diff_eq!(edge.distance_2(&[0.0, 0.5]), 0.5 * 0.5); + assert_abs_diff_eq!(edge.distance_2(&[0.5, 1.0]), 0.0); + assert_abs_diff_eq!(edge.distance_2(&[0.0, 0.0]), 0.5); + assert_abs_diff_eq!(edge.distance_2(&[0.0, 1.0]), 0.5 * 0.5); + assert_abs_diff_eq!(edge.distance_2(&[1.0, 1.0]), 0.5 * 0.5); + assert_abs_diff_eq!(edge.distance_2(&[1.0, 3.0]), 0.5 * 0.5 + 1.0); + } + + #[test] + fn container_length_2() { + let line = CachedEnvelope::new(Line::new([1, -1], [5, 5])); + + assert_eq!(line.length_2(), 16 + 36); + } + + #[test] + fn container_nearest_neighbour() { + let mut lines = RTree::new(); + lines.insert(GeomWithData::new( + CachedEnvelope::new(Line::new([0.0, 0.0], [1.0, 1.0])), + "Line A", + )); + lines.insert(GeomWithData::new( + CachedEnvelope::new(Line::new([0.0, 0.0], [-1.0, 1.0])), + "Line B", + )); + let my_location = [0.0, 0.0]; + // Now find the closest line + let place = lines.nearest_neighbor(&my_location).unwrap(); + + assert_eq!(place.data, "Line A"); + } +} diff --git a/thirdparty/rstar/src/primitives/geom_with_data.rs b/thirdparty/rstar/src/primitives/geom_with_data.rs new file mode 100644 index 0000000..5046f5e --- /dev/null +++ b/thirdparty/rstar/src/primitives/geom_with_data.rs @@ -0,0 +1,136 @@ +use crate::envelope::Envelope; +use crate::object::PointDistance; +use crate::{object::RTreeObject, point::Point}; + +/// An [RTreeObject] with a geometry and some associated data that can be inserted into an r-tree. +/// +/// Often, adding metadata (like a database ID) to a geometry is required before adding it +/// into an r-tree. This struct removes some of the boilerplate required to do so. +/// +/// **Note:** while the container itself implements [RTreeObject], you will have to go through its +/// [`geom`][Self::geom] method in order to access geometry-specific methods. +/// +/// # Example +/// ``` +/// use rstar::{RTree, PointDistance}; +/// use rstar::primitives::GeomWithData; +/// +/// type RestaurantLocation = GeomWithData<[f64; 2], &'static str>; +/// +/// let mut restaurants = RTree::new(); +/// restaurants.insert(RestaurantLocation::new([0.3, 0.2], "Pete's Pizza Place")); +/// restaurants.insert(RestaurantLocation::new([-0.8, 0.0], "The Great Steak")); +/// restaurants.insert(RestaurantLocation::new([0.2, -0.2], "Fishy Fortune")); +/// +/// let my_location = [0.0, 0.0]; +/// +/// // Now find the closest restaurant! +/// let place = restaurants.nearest_neighbor(&my_location).unwrap(); +/// println!("Let's go to {}", place.data); +/// println!("It's really close, only {} miles", place.distance_2(&my_location)); +/// ``` +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct GeomWithData { + geom: R, + /// Data to be associated with the geometry being stored in the [`RTree`](crate::RTree). + pub data: T, +} + +impl RTreeObject for GeomWithData { + type Envelope = R::Envelope; + + fn envelope(&self) -> Self::Envelope { + self.geom.envelope() + } +} + +impl PointDistance for GeomWithData { + fn distance_2( + &self, + point: &::Point, + ) -> <::Point as Point>::Scalar { + self.geom.distance_2(point) + } + + fn contains_point(&self, p: &::Point) -> bool { + self.geom.contains_point(p) + } + + fn distance_2_if_less_or_equal( + &self, + point: &::Point, + max_distance_2: <::Point as Point>::Scalar, + ) -> Option<<::Point as Point>::Scalar> { + self.geom.distance_2_if_less_or_equal(point, max_distance_2) + } +} + +impl GeomWithData { + /// Create a new [GeomWithData] struct using the provided geometry and data. + pub fn new(geom: R, data: T) -> Self { + Self { geom, data } + } + + /// Get a reference to the container's geometry. + pub fn geom(&self) -> &R { + &self.geom + } +} + +#[cfg(test)] +mod test { + use super::GeomWithData; + use crate::object::PointDistance; + + use approx::*; + + use crate::{primitives::Line, RTree}; + + #[test] + fn container_in_rtree() { + let line_1 = GeomWithData::new(Line::new([0.0, 0.0], [1.0, 1.0]), ()); + let line_2 = GeomWithData::new(Line::new([0.0, 0.0], [-1.0, 1.0]), ()); + let tree = RTree::bulk_load(vec![line_1, line_2]); + + assert!(tree.contains(&line_1)); + } + + #[test] + fn container_edge_distance() { + let edge = GeomWithData::new(Line::new([0.5, 0.5], [0.5, 2.0]), 1usize); + + assert_abs_diff_eq!(edge.distance_2(&[0.5, 0.5]), 0.0); + assert_abs_diff_eq!(edge.distance_2(&[0.0, 0.5]), 0.5 * 0.5); + assert_abs_diff_eq!(edge.distance_2(&[0.5, 1.0]), 0.0); + assert_abs_diff_eq!(edge.distance_2(&[0.0, 0.0]), 0.5); + assert_abs_diff_eq!(edge.distance_2(&[0.0, 1.0]), 0.5 * 0.5); + assert_abs_diff_eq!(edge.distance_2(&[1.0, 1.0]), 0.5 * 0.5); + assert_abs_diff_eq!(edge.distance_2(&[1.0, 3.0]), 0.5 * 0.5 + 1.0); + } + + #[test] + fn container_length_2() { + let line = GeomWithData::new(Line::new([1, -1], [5, 5]), 1usize); + + assert_eq!(line.geom().length_2(), 16 + 36); + } + + #[test] + fn container_nearest_neighbour() { + let mut lines = RTree::new(); + lines.insert(GeomWithData::new( + Line::new([0.0, 0.0], [1.0, 1.0]), + "Line A", + )); + lines.insert(GeomWithData::new( + Line::new([0.0, 0.0], [-1.0, 1.0]), + "Line B", + )); + let my_location = [0.0, 0.0]; + // Now find the closest line + let place = lines.nearest_neighbor(&my_location).unwrap(); + + assert_eq!(place.data, "Line A"); + } +} diff --git a/thirdparty/rstar/src/primitives/line.rs b/thirdparty/rstar/src/primitives/line.rs new file mode 100644 index 0000000..8999268 --- /dev/null +++ b/thirdparty/rstar/src/primitives/line.rs @@ -0,0 +1,142 @@ +use crate::aabb::AABB; +use crate::envelope::Envelope; +use crate::object::PointDistance; +use crate::object::RTreeObject; +use crate::point::{Point, PointExt}; +use num_traits::{One, Zero}; + +/// A line defined by a start and and end point. +/// +/// This struct can be inserted directly into an r-tree. +/// # Type parameters +/// `P`: The line's [Point] type. +/// +/// # Example +/// ``` +/// use rstar::primitives::Line; +/// use rstar::{RTree, RTreeObject}; +/// +/// let line_1 = Line::new([0.0, 0.0], [1.0, 1.0]); +/// let line_2 = Line::new([0.0, 0.0], [-1.0, 1.0]); +/// let tree = RTree::bulk_load(vec![line_1, line_2]); +/// +/// assert!(tree.contains(&line_1)); +/// ``` +#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct Line

+where + P: Point, +{ + /// The line's start point + pub from: P, + /// The line's end point. + pub to: P, +} + +impl

Line

+where + P: Point, +{ + /// Creates a new line between two points. + pub fn new(from: P, to: P) -> Self { + Line { from, to } + } +} + +impl

RTreeObject for Line

+where + P: Point, +{ + type Envelope = AABB

; + + fn envelope(&self) -> Self::Envelope { + AABB::from_corners(self.from.clone(), self.to.clone()) + } +} + +impl

Line

+where + P: Point, +{ + /// Returns the squared length of this line. + /// + /// # Example + /// ``` + /// use rstar::primitives::Line; + /// + /// let line = Line::new([3, 3], [7, 6]); + /// assert_eq!(line.length_2(), 25); + /// ``` + pub fn length_2(&self) -> P::Scalar { + self.from.sub(&self.to).length_2() + } + + fn project_point(&self, query_point: &P) -> P::Scalar { + let (ref p1, ref p2) = (self.from.clone(), self.to.clone()); + let dir = p2.sub(p1); + query_point.sub(p1).dot(&dir) / dir.length_2() + } + + /// Returns the nearest point on this line relative to a given point. + /// + /// # Example + /// ``` + /// use rstar::primitives::Line; + /// + /// let line = Line::new([0.0, 0.0], [1., 1.]); + /// assert_eq!(line.nearest_point(&[0.0, 0.0]), [0.0, 0.0]); + /// assert_eq!(line.nearest_point(&[1.0, 0.0]), [0.5, 0.5]); + /// assert_eq!(line.nearest_point(&[10., 12.]), [1.0, 1.0]); + /// ``` + pub fn nearest_point(&self, query_point: &P) -> P { + let (p1, p2) = (self.from.clone(), self.to.clone()); + let dir = p2.sub(&p1); + let s = self.project_point(query_point); + if P::Scalar::zero() < s && s < One::one() { + p1.add(&dir.mul(s)) + } else if s <= P::Scalar::zero() { + p1 + } else { + p2 + } + } +} + +impl

PointDistance for Line

+where + P: Point, +{ + fn distance_2( + &self, + point: &::Point, + ) -> <::Point as Point>::Scalar { + self.nearest_point(point).sub(point).length_2() + } +} + +#[cfg(test)] +mod test { + use super::Line; + use crate::object::PointDistance; + use approx::*; + + #[test] + fn edge_distance() { + let edge = Line::new([0.5, 0.5], [0.5, 2.0]); + + assert_abs_diff_eq!(edge.distance_2(&[0.5, 0.5]), 0.0); + assert_abs_diff_eq!(edge.distance_2(&[0.0, 0.5]), 0.5 * 0.5); + assert_abs_diff_eq!(edge.distance_2(&[0.5, 1.0]), 0.0); + assert_abs_diff_eq!(edge.distance_2(&[0.0, 0.0]), 0.5); + assert_abs_diff_eq!(edge.distance_2(&[0.0, 1.0]), 0.5 * 0.5); + assert_abs_diff_eq!(edge.distance_2(&[1.0, 1.0]), 0.5 * 0.5); + assert_abs_diff_eq!(edge.distance_2(&[1.0, 3.0]), 0.5 * 0.5 + 1.0); + } + + #[test] + fn length_2() { + let line = Line::new([1, -1], [5, 5]); + assert_eq!(line.length_2(), 16 + 36); + } +} diff --git a/thirdparty/rstar/src/primitives/mod.rs b/thirdparty/rstar/src/primitives/mod.rs new file mode 100644 index 0000000..27e1ebc --- /dev/null +++ b/thirdparty/rstar/src/primitives/mod.rs @@ -0,0 +1,15 @@ +//! Contains primitives ready for insertion into an r-tree. + +mod cached_envelope; +mod geom_with_data; +mod line; +mod object_ref; +mod point_with_data; +mod rectangle; + +pub use self::cached_envelope::CachedEnvelope; +pub use self::geom_with_data::GeomWithData; +pub use self::line::Line; +pub use self::object_ref::ObjectRef; +pub use self::point_with_data::PointWithData; +pub use self::rectangle::Rectangle; diff --git a/thirdparty/rstar/src/primitives/object_ref.rs b/thirdparty/rstar/src/primitives/object_ref.rs new file mode 100644 index 0000000..0608d81 --- /dev/null +++ b/thirdparty/rstar/src/primitives/object_ref.rs @@ -0,0 +1,62 @@ +use crate::envelope::Envelope; +use crate::object::PointDistance; +use crate::{object::RTreeObject, point::Point}; +use core::ops::Deref; + +/// An [RTreeObject] that is a possibly short-lived reference to another object. +/// +/// Sometimes it can be useful to build an [RTree] that does not own its constituent +/// objects but references them from elsewhere. Wrapping the bare references with this +/// combinator makes this possible. +/// +/// **Note:** the wrapper implements [RTreeObject] and referenced object `T` can be +/// accessed via an implementation of `Deref`. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ObjectRef<'a, T: RTreeObject> { + inner: &'a T, +} + +impl<'a, T: RTreeObject> RTreeObject for ObjectRef<'a, T> { + type Envelope = T::Envelope; + + fn envelope(&self) -> Self::Envelope { + self.inner.envelope() + } +} + +impl<'a, T: PointDistance> PointDistance for ObjectRef<'a, T> { + fn distance_2( + &self, + point: &::Point, + ) -> <::Point as Point>::Scalar { + self.inner.distance_2(point) + } + + fn contains_point(&self, p: &::Point) -> bool { + self.inner.contains_point(p) + } + + fn distance_2_if_less_or_equal( + &self, + point: &::Point, + max_distance_2: <::Point as Point>::Scalar, + ) -> Option<<::Point as Point>::Scalar> { + self.inner + .distance_2_if_less_or_equal(point, max_distance_2) + } +} + +impl<'a, T: RTreeObject> ObjectRef<'a, T> { + /// Create a new [ObjectRef] struct using the object. + pub fn new(inner: &'a T) -> Self { + Self { inner } + } +} + +impl<'a, T: RTreeObject> Deref for ObjectRef<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.inner + } +} diff --git a/thirdparty/rstar/src/primitives/point_with_data.rs b/thirdparty/rstar/src/primitives/point_with_data.rs new file mode 100644 index 0000000..9ba54a3 --- /dev/null +++ b/thirdparty/rstar/src/primitives/point_with_data.rs @@ -0,0 +1,72 @@ +use crate::{Point, PointDistance, RTreeObject, AABB}; + +/// A point with some associated data that can be inserted into an r-tree. +/// +/// **Note**: `PointWithData` has been deprecated in favour of [`GeomWithData`](crate::primitives::GeomWithData) +/// +/// Often, adding metadata (like a database index) to a point is required before adding them +/// into an r-tree. This struct removes some of the boilerplate required to do so. +/// +/// # Example +/// ``` +/// use rstar::{RTree, PointDistance}; +/// use rstar::primitives::PointWithData; +/// +/// type RestaurantLocation = PointWithData<&'static str, [f64; 2]>; +/// +/// let mut restaurants = RTree::new(); +/// restaurants.insert(RestaurantLocation::new("Pete's Pizza Place", [0.3, 0.2])); +/// restaurants.insert(RestaurantLocation::new("The Great Steak", [-0.8, 0.0])); +/// restaurants.insert(RestaurantLocation::new("Fishy Fortune", [0.2, -0.2])); +/// +/// let my_location = [0.0, 0.0]; +/// +/// // Now find the closest restaurant! +/// let place = restaurants.nearest_neighbor(&my_location).unwrap(); +/// println!("Let's go to {}", place.data); +/// println!("It's really close, only {} miles", place.distance_2(&my_location)) +/// ``` +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct PointWithData { + /// Any data associated with a point. + pub data: T, + point: P, // Private to prevent modification. +} + +impl PointWithData { + /// Creates a new `PointWithData` with the provided data. + #[deprecated(note = "`PointWithData` is deprecated. Please switch to `GeomWithData`")] + pub fn new(data: T, point: P) -> Self { + PointWithData { data, point } + } + + /// Returns this point's position. + pub fn position(&self) -> &P { + &self.point + } +} + +impl RTreeObject for PointWithData +where + P: Point, +{ + type Envelope = AABB

; + + fn envelope(&self) -> Self::Envelope { + self.point.envelope() + } +} + +impl PointDistance for PointWithData +where + P: Point, +{ + fn distance_2(&self, point: &P) ->

::Scalar { + self.point.distance_2(point) + } + + fn contains_point(&self, point: &P) -> bool { + self.point.contains_point(point) + } +} diff --git a/thirdparty/rstar/src/primitives/rectangle.rs b/thirdparty/rstar/src/primitives/rectangle.rs new file mode 100644 index 0000000..6e1d0ba --- /dev/null +++ b/thirdparty/rstar/src/primitives/rectangle.rs @@ -0,0 +1,134 @@ +use crate::aabb::AABB; +use crate::envelope::Envelope; +use crate::object::{PointDistance, RTreeObject}; +use crate::point::{Point, PointExt}; + +/// An n-dimensional rectangle defined by its two corners. +/// +/// This rectangle can be directly inserted into an r-tree. +/// +/// *Note*: Despite being called rectangle, this struct can be used +/// with more than two dimensions by using an appropriate point type. +/// +/// # Type parameters +/// `P`: The rectangle's [Point] type. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct Rectangle

+where + P: Point, +{ + aabb: AABB

, +} + +impl

Rectangle

+where + P: Point, +{ + /// Creates a new rectangle defined by two corners. + pub fn from_corners(corner_1: P, corner_2: P) -> Self { + AABB::from_corners(corner_1, corner_2).into() + } + + /// Creates a new rectangle defined by it's [axis aligned bounding box(AABB). + pub fn from_aabb(aabb: AABB

) -> Self { + Rectangle { aabb } + } + + /// Returns the rectangle's lower corner. + /// + /// This is the point contained within the rectangle with the smallest coordinate value in each + /// dimension. + pub fn lower(&self) -> P { + self.aabb.lower() + } + + /// Returns the rectangle's upper corner. + /// + /// This is the point contained within the AABB with the largest coordinate value in each + /// dimension. + pub fn upper(&self) -> P { + self.aabb.upper() + } +} + +impl

From> for Rectangle

+where + P: Point, +{ + fn from(aabb: AABB

) -> Self { + Self::from_aabb(aabb) + } +} + +impl

RTreeObject for Rectangle

+where + P: Point, +{ + type Envelope = AABB

; + + fn envelope(&self) -> Self::Envelope { + self.aabb.clone() + } +} + +impl

Rectangle

+where + P: Point, +{ + /// Returns the nearest point within this rectangle to a given point. + /// + /// If `query_point` is contained within this rectangle, `query_point` is returned. + pub fn nearest_point(&self, query_point: &P) -> P { + self.aabb.min_point(query_point) + } +} + +impl

PointDistance for Rectangle

+where + P: Point, +{ + fn distance_2( + &self, + point: &::Point, + ) -> <::Point as Point>::Scalar { + self.nearest_point(point).sub(point).length_2() + } + + fn contains_point(&self, point: &::Point) -> bool { + self.aabb.contains_point(point) + } + + fn distance_2_if_less_or_equal( + &self, + point: &::Point, + max_distance_2: <::Point as Point>::Scalar, + ) -> Option<<::Point as Point>::Scalar> { + let distance_2 = self.distance_2(point); + if distance_2 <= max_distance_2 { + Some(distance_2) + } else { + None + } + } +} + +#[cfg(test)] +mod test { + use super::Rectangle; + use crate::object::PointDistance; + use approx::*; + + #[test] + fn rectangle_distance() { + let rectangle = Rectangle::from_corners([0.5, 0.5], [1.0, 2.0]); + + assert_abs_diff_eq!(rectangle.distance_2(&[0.5, 0.5]), 0.0); + assert_abs_diff_eq!(rectangle.distance_2(&[0.0, 0.5]), 0.5 * 0.5); + assert_abs_diff_eq!(rectangle.distance_2(&[0.5, 1.0]), 0.0); + assert_abs_diff_eq!(rectangle.distance_2(&[0.0, 0.0]), 0.5); + assert_abs_diff_eq!(rectangle.distance_2(&[0.0, 1.0]), 0.5 * 0.5); + assert_abs_diff_eq!(rectangle.distance_2(&[1.0, 3.0]), 1.0); + assert_abs_diff_eq!(rectangle.distance_2(&[1.0, 1.0]), 0.0); + } +} diff --git a/thirdparty/rstar/src/rtree.rs b/thirdparty/rstar/src/rtree.rs new file mode 100644 index 0000000..862afa9 --- /dev/null +++ b/thirdparty/rstar/src/rtree.rs @@ -0,0 +1,1167 @@ +use crate::algorithm::bulk_load; +use crate::algorithm::iterators::*; +use crate::algorithm::nearest_neighbor; +use crate::algorithm::nearest_neighbor::NearestNeighborDistance2Iterator; +use crate::algorithm::nearest_neighbor::NearestNeighborIterator; +use crate::algorithm::removal; +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::Point; +use core::ops::ControlFlow; + +#[cfg(not(test))] +use alloc::vec::Vec; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +impl Default for RTree +where + T: RTreeObject, + Params: RTreeParams, +{ + fn default() -> Self { + Self::new_with_params() + } +} + +/// An n-dimensional r-tree data structure. +/// +/// # R-Trees +/// R-Trees are data structures containing multi-dimensional objects like points, rectangles +/// or polygons. They are optimized for retrieving the nearest neighbor at any point. +/// +/// R-trees can efficiently find answers to queries like "Find the nearest point of a polygon", +/// "Find all police stations within a rectangle" or "Find the 10 nearest restaurants, sorted +/// by their distances". Compared to a naive implementation for these scenarios that runs +/// in `O(n)` for `n` inserted elements, r-trees reduce this time to `O(log(n))`. +/// +/// However, creating an r-tree is time consuming +/// and runs in `O(n * log(n))`. Thus, r-trees are suited best if many queries and only few +/// insertions are made. `rstar` also supports [bulk loading](RTree::bulk_load), +/// which cuts down the constant factors when creating an r-tree significantly compared to +/// sequential insertions. +/// +/// R-trees are also _dynamic_: points can be inserted and removed from an existing tree. +/// +/// ## Partitioning heuristics +/// The inserted objects are internally partitioned into several boxes which should have small +/// overlap and volume. This is done heuristically. While the originally proposed heuristic focused +/// on fast insertion operations, the resulting r-trees were often suboptimally structured. Another +/// heuristic, called `R*-tree` (r-star-tree), was proposed to improve the tree structure at the cost of +/// longer insertion operations and is currently the crate's only implemented +/// [InsertionStrategy]. +/// +/// # Usage +/// The items inserted into an r-tree must implement the [RTreeObject] +/// trait. To support nearest neighbor queries, implement the [PointDistance] +/// trait. Some useful geometric primitives that implement the above traits can be found in the +/// [crate::primitives] module. Several primitives in the [`geo-types`](https://docs.rs/geo-types/) crate also +/// implement these traits. +/// +/// ## Example +/// ``` +/// use rstar::RTree; +/// +/// let mut tree = RTree::new(); +/// tree.insert([0.1, 0.0f32]); +/// tree.insert([0.2, 0.1]); +/// tree.insert([0.3, 0.0]); +/// +/// assert_eq!(tree.nearest_neighbor(&[0.4, -0.1]), Some(&[0.3, 0.0])); +/// tree.remove(&[0.3, 0.0]); +/// assert_eq!(tree.nearest_neighbor(&[0.4, 0.3]), Some(&[0.2, 0.1])); +/// +/// assert_eq!(tree.size(), 2); +/// // &RTree implements IntoIterator! +/// for point in &tree { +/// println!("Tree contains a point {:?}", point); +/// } +/// ``` +/// +/// ## Supported point types +/// All types implementing the [Point] trait can be used as underlying point type. +/// By default, fixed size arrays can be used as points. +/// +/// # Associating Data with Geometries +/// Users wishing to store associated data with geometries can use [crate::primitives::GeomWithData]. +/// +/// # Runtime and Performance +/// The runtime of query operations (e.g. `nearest neighbor` or `contains`) is usually +/// `O(log(n))`, where `n` refers to the number of elements contained in the r-tree. +/// A naive sequential algorithm would take `O(n)` time. However, r-trees incur higher +/// build up times: inserting an element into an r-tree costs `O(log(n))` time. +/// +/// Most of the selection methods, meaning those with names beginning with `locate_`, +/// return iterators which are driven externally and can therefore be combined into +/// more complex pipelines using the combinators defined on the [`Iterator`] trait. +/// +/// This flexiblity does come at the cost of temporary heap allocations required +/// to keep track of the iteration state. Alternative methods using internal iteration +/// are provided to avoid this overhead, their names ending in `_int` or `_int_mut`. +/// +/// They use a callback-based interface to pass the selected objects on to the caller +/// thereby being able to use the stack to keep track of the state required for +/// traversing the tree. +/// +/// # Bulk loading +/// In many scenarios, insertion is only carried out once for many points. In this case, +/// [RTree::bulk_load] will be considerably faster. Its total run time +/// is still `O(nlog(n))`, i.e. `O(log(n))` per element inserted, but the scaling +/// factor is, on average, significantly improved compared with performing single +/// insertion n times in a row. **Note the performance caveat +/// related to the computation of the envelope**. +/// +/// # Element distribution +/// The tree's performance heavily relies on the spatial distribution of its elements. +/// Best performance is achieved if: +/// * No element is inserted more than once +/// * The overlapping area of elements is as small as +/// possible. +/// +/// For the edge case that all elements are overlapping (e.g, one and the same element +/// is contained `n` times), the performance of most operations usually degrades to `O(n)`. +/// +/// # Type Parameters +/// * `T`: The type of objects stored in the r-tree. +/// * `Params`: Compile time parameters that change the r-tree's internal layout. Refer to the +/// [RTreeParams] trait for more information. +/// +/// # Defining methods generic over r-trees +/// 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) +/// where +/// T: RTreeObject, +/// Params: RTreeParams +/// { +/// // ... +/// } +/// ``` +/// Otherwise, any user of `generic_rtree_function` would be forced to use +/// a tree with default parameters. +/// +/// # (De)Serialization +/// Enable the `serde` feature for [Serde](https://crates.io/crates/serde) support. +/// +/// ## Further reading +/// For more information refer to the [wikipedia article](https://en.wikipedia.org/wiki/R-tree). +/// +#[derive(Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr( + feature = "serde", + serde(bound( + serialize = "T: Serialize, T::Envelope: Serialize", + deserialize = "T: Deserialize<'de>, T::Envelope: Deserialize<'de>" + )) +)] +pub struct RTree +where + Params: RTreeParams, + T: RTreeObject, +{ + root: ParentNode, + size: usize, + _params: ::core::marker::PhantomData, +} + +struct DebugHelper<'a, T, Params> +where + T: RTreeObject + ::core::fmt::Debug + 'a, + Params: RTreeParams + 'a, +{ + rtree: &'a RTree, +} + +impl<'a, T, Params> ::core::fmt::Debug for DebugHelper<'a, T, Params> +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 +where + Params: RTreeParams, + T: RTreeObject + ::core::fmt::Debug, +{ + fn fmt(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + formatter + .debug_struct("RTree") + .field("size", &self.size) + .field("items", &DebugHelper { rtree: self }) + .finish() + } +} + +impl RTree +where + T: RTreeObject, +{ + /// Creates a new, empty r-tree. + /// + /// The created r-tree is configured with [default parameters](DefaultParams). + pub fn new() -> Self { + Self::new_with_params() + } + + /// Creates a new r-tree with some elements already inserted. + /// + /// This method should be the preferred way for creating r-trees. It both + /// runs faster and yields an r-tree with better internal structure that + /// improves query performance. + /// + /// This method implements the overlap minimizing top-down bulk loading algorithm (OMT) + /// as described in [this paper by Lee and Lee (2003)](http://ceur-ws.org/Vol-74/files/FORUM_18.pdf). + /// + /// # Runtime + /// Bulk loading runs in `O(n * log(n))`, where `n` is the number of loaded + /// elements. + /// + /// # Note + /// The envelope of each element will be accessed many times during loading. If that computation + /// is expensive, **consider memoizing it** using [`CachedEnvelope`][crate::primitives::CachedEnvelope]. + pub fn bulk_load(elements: Vec) -> Self { + Self::bulk_load_with_params(elements) + } +} + +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::(); + RTree { + root: ParentNode::new_root::(), + size: 0, + _params: Default::default(), + } + } + + /// Creates a new r-tree with some given elements and configurable parameters. + /// + /// 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>) + } + + /// Returns the number of objects in an r-tree. + /// + /// # Example + /// ``` + /// use rstar::RTree; + /// + /// let mut tree = RTree::new(); + /// assert_eq!(tree.size(), 0); + /// tree.insert([0.0, 1.0, 2.0]); + /// assert_eq!(tree.size(), 1); + /// tree.remove(&[0.0, 1.0, 2.0]); + /// assert_eq!(tree.size(), 0); + /// ``` + pub fn size(&self) -> usize { + self.size + } + + pub(crate) fn size_mut(&mut self) -> &mut usize { + &mut self.size + } + + /// Returns an iterator over all elements contained in the tree. + /// + /// The order in which the elements are returned is not specified. + /// + /// # Example + /// ``` + /// use rstar::RTree; + /// let tree = RTree::bulk_load(vec![(0.0, 0.1), (0.3, 0.2), (0.4, 0.2)]); + /// for point in tree.iter() { + /// println!("This tree contains point {:?}", point); + /// } + /// ``` + pub fn iter(&self) -> RTreeIterator { + RTreeIterator::new(&self.root, SelectAllFunc) + } + + /// Returns an iterator over all mutable elements contained in the tree. + /// + /// The order in which the elements are returned is not specified. + /// + /// *Note*: It is a logic error to change an inserted item's position or dimensions. This + /// method is primarily meant for own implementations of [RTreeObject] + /// which can contain arbitrary additional data. + /// If the position or location of an inserted object need to change, you will need to [RTree::remove] + /// and reinsert it. + /// + pub fn iter_mut(&mut self) -> RTreeIteratorMut { + RTreeIteratorMut::new(&mut self.root, SelectAllFunc) + } + + /// Returns all elements contained in an [Envelope]. + /// + /// Usually, an envelope is an [axis aligned bounding box](crate::AABB). This + /// method can be used to retrieve all elements that are fully contained within an envelope. + /// + /// # Example + /// ``` + /// use rstar::{RTree, AABB}; + /// let mut tree = RTree::bulk_load(vec![ + /// [0.0, 0.0], + /// [0.0, 1.0], + /// [1.0, 1.0] + /// ]); + /// let half_unit_square = AABB::from_corners([0.0, 0.0], [0.5, 1.0]); + /// let unit_square = AABB::from_corners([0.0, 0.0], [1.0, 1.0]); + /// let elements_in_half_unit_square = tree.locate_in_envelope(&half_unit_square); + /// let elements_in_unit_square = tree.locate_in_envelope(&unit_square); + /// assert_eq!(elements_in_half_unit_square.count(), 2); + /// assert_eq!(elements_in_unit_square.count(), 3); + /// ``` + pub fn locate_in_envelope(&self, envelope: &T::Envelope) -> LocateInEnvelope { + LocateInEnvelope::new(&self.root, SelectInEnvelopeFunction::new(envelope.clone())) + } + + /// Mutable variant of [locate_in_envelope](#method.locate_in_envelope). + pub fn locate_in_envelope_mut(&mut self, envelope: &T::Envelope) -> LocateInEnvelopeMut { + LocateInEnvelopeMut::new( + &mut self.root, + SelectInEnvelopeFunction::new(envelope.clone()), + ) + } + + /// Variant of [`locate_in_envelope`][Self::locate_in_envelope] using internal iteration. + pub fn locate_in_envelope_int<'a, V, B>( + &'a self, + envelope: &T::Envelope, + mut visitor: V, + ) -> ControlFlow + where + V: FnMut(&'a T) -> ControlFlow, + { + select_nodes( + self.root(), + &SelectInEnvelopeFunction::new(envelope.clone()), + &mut visitor, + ) + } + + /// Mutable variant of [`locate_in_envelope_mut`][Self::locate_in_envelope_mut]. + pub fn locate_in_envelope_int_mut<'a, V, B>( + &'a mut self, + envelope: &T::Envelope, + mut visitor: V, + ) -> ControlFlow + where + V: FnMut(&'a mut T) -> ControlFlow, + { + select_nodes_mut( + self.root_mut(), + &SelectInEnvelopeFunction::new(envelope.clone()), + &mut visitor, + ) + } + + /// Returns a draining iterator over all elements contained in the tree. + /// + /// The order in which the elements are returned is not specified. + /// + /// See + /// [drain_with_selection_function](#method.drain_with_selection_function) + /// for more information. + pub fn drain(&mut self) -> DrainIterator { + self.drain_with_selection_function(SelectAllFunc) + } + + /// Draining variant of [locate_in_envelope](#method.locate_in_envelope). + pub fn drain_in_envelope( + &mut self, + envelope: T::Envelope, + ) -> DrainIterator, Params> { + let sel = SelectInEnvelopeFunction::new(envelope); + self.drain_with_selection_function(sel) + } + + /// Returns all elements whose envelope intersects a given envelope. + /// + /// Any element fully contained within an envelope is also returned by this method. Two + /// envelopes that "touch" each other (e.g. by sharing only a common corner) are also + /// considered to intersect. Usually, an envelope is an [axis aligned bounding box](crate::AABB). + /// This method will return all elements whose AABB has some common area with + /// a given AABB. + /// + /// # Example + /// ``` + /// use rstar::{RTree, AABB}; + /// use rstar::primitives::Rectangle; + /// + /// let left_piece = AABB::from_corners([0.0, 0.0], [0.4, 1.0]); + /// let right_piece = AABB::from_corners([0.6, 0.0], [1.0, 1.0]); + /// let middle_piece = AABB::from_corners([0.25, 0.0], [0.75, 1.0]); + /// + /// let mut tree = RTree::>::bulk_load(vec![ + /// left_piece.into(), + /// right_piece.into(), + /// middle_piece.into(), + /// ]); + /// + /// let elements_intersecting_left_piece = tree.locate_in_envelope_intersecting(&left_piece); + /// // The left piece should not intersect the right piece! + /// assert_eq!(elements_intersecting_left_piece.count(), 2); + /// let elements_intersecting_middle = tree.locate_in_envelope_intersecting(&middle_piece); + /// // Only the middle piece intersects all pieces within the tree + /// assert_eq!(elements_intersecting_middle.count(), 3); + /// + /// let large_piece = AABB::from_corners([-100., -100.], [100., 100.]); + /// let elements_intersecting_large_piece = tree.locate_in_envelope_intersecting(&large_piece); + /// // Any element that is fully contained should also be returned: + /// assert_eq!(elements_intersecting_large_piece.count(), 3); + /// ``` + pub fn locate_in_envelope_intersecting( + &self, + envelope: &T::Envelope, + ) -> LocateInEnvelopeIntersecting { + LocateInEnvelopeIntersecting::new( + &self.root, + SelectInEnvelopeFuncIntersecting::new(envelope.clone()), + ) + } + + /// Mutable variant of [locate_in_envelope_intersecting](#method.locate_in_envelope_intersecting) + pub fn locate_in_envelope_intersecting_mut( + &mut self, + envelope: &T::Envelope, + ) -> LocateInEnvelopeIntersectingMut { + LocateInEnvelopeIntersectingMut::new( + &mut self.root, + SelectInEnvelopeFuncIntersecting::new(envelope.clone()), + ) + } + + /// Variant of [`locate_in_envelope_intersecting`][Self::locate_in_envelope_intersecting] using internal iteration. + pub fn locate_in_envelope_intersecting_int<'a, V, B>( + &'a self, + envelope: &T::Envelope, + mut visitor: V, + ) -> ControlFlow + where + V: FnMut(&'a T) -> ControlFlow, + { + select_nodes( + self.root(), + &SelectInEnvelopeFuncIntersecting::new(envelope.clone()), + &mut visitor, + ) + } + + /// Mutable variant of [`locate_in_envelope_intersecting_int`][Self::locate_in_envelope_intersecting_int]. + pub fn locate_in_envelope_intersecting_int_mut<'a, V, B>( + &'a mut self, + envelope: &T::Envelope, + mut visitor: V, + ) -> ControlFlow + where + V: FnMut(&'a mut T) -> ControlFlow, + { + select_nodes_mut( + self.root_mut(), + &SelectInEnvelopeFuncIntersecting::new(envelope.clone()), + &mut visitor, + ) + } + + /// Locates elements in the r-tree defined by a selection function. + /// + /// Refer to the documentation of [`SelectionFunction`] for + /// more information. + /// + /// Usually, other `locate` methods should cover most common use cases. This method is only required + /// in more specific situations. + pub fn locate_with_selection_function>( + &self, + selection_function: S, + ) -> SelectionIterator { + SelectionIterator::new(&self.root, selection_function) + } + + /// Mutable variant of [`locate_with_selection_function`](#method.locate_with_selection_function). + pub fn locate_with_selection_function_mut>( + &mut self, + selection_function: S, + ) -> SelectionIteratorMut { + SelectionIteratorMut::new(&mut self.root, selection_function) + } + + /// Returns all possible intersecting objects of this and another tree. + /// + /// This will return all objects whose _envelopes_ intersect. No geometric intersection + /// checking is performed. + pub fn intersection_candidates_with_other_tree<'a, U>( + &'a self, + other: &'a RTree, + ) -> IntersectionIterator<'a, T, U> + where + U: RTreeObject, + { + IntersectionIterator::new(self.root(), other.root()) + } + + /// Returns the tree's root node. + /// + /// Usually, you will not need to call this method. However, for debugging purposes or for + /// advanced algorithms, knowledge about the tree's internal structure may be required. + /// For these cases, this method serves as an entry point. + pub fn root(&self) -> &ParentNode { + &self.root + } + + pub(crate) fn root_mut(&mut self) -> &mut ParentNode { + &mut self.root + } + + fn new_from_bulk_loading( + elements: Vec, + root_loader: impl Fn(Vec) -> ParentNode, + ) -> Self { + verify_parameters::(); + let size = elements.len(); + let root = if size == 0 { + ParentNode::new_root::() + } else { + root_loader(elements) + }; + RTree { + root, + size, + _params: Default::default(), + } + } + + /// Removes and returns a single element from the tree. The element to remove is specified + /// by a [`SelectionFunction`]. + /// + /// See also: [`RTree::remove`], [`RTree::remove_at_point`] + /// + pub fn remove_with_selection_function(&mut self, function: F) -> Option + where + F: SelectionFunction, + { + removal::DrainIterator::new(self, function).take(1).last() + } + + /// Drain elements selected by a [`SelectionFunction`]. Returns an + /// iterator that successively removes selected elements and returns + /// them. This is the most generic drain API, see also: + /// [`RTree::drain_in_envelope_intersecting`], + /// [`RTree::drain_within_distance`]. + /// + /// # Remarks + /// + /// This API is similar to `Vec::drain_filter`, but stopping the + /// 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 + where + F: SelectionFunction, + { + removal::DrainIterator::new(self, function) + } + + /// Drains elements intersecting the `envelope`. Similar to + /// `locate_in_envelope_intersecting`, except the elements are removed + /// and returned via an iterator. + pub fn drain_in_envelope_intersecting( + &mut self, + envelope: T::Envelope, + ) -> DrainIterator, Params> { + let selection_function = SelectInEnvelopeFuncIntersecting::new(envelope); + self.drain_with_selection_function(selection_function) + } +} + +impl RTree +where + Params: RTreeParams, + T: PointDistance, +{ + /// Returns a single object that covers a given point. + /// + /// Method [contains_point](PointDistance::contains_point) + /// is used to determine if a tree element contains the given point. + /// + /// If multiple elements contain the given point, any of them is returned. + pub fn locate_at_point(&self, point: &::Point) -> Option<&T> { + self.locate_all_at_point(point).next() + } + + /// Mutable variant of [RTree::locate_at_point]. + pub fn locate_at_point_mut( + &mut self, + point: &::Point, + ) -> Option<&mut T> { + self.locate_all_at_point_mut(point).next() + } + + /// Variant of [`locate_at_point`][Self::locate_at_point] using internal iteration. + pub fn locate_at_point_int(&self, point: &::Point) -> Option<&T> { + match self.locate_all_at_point_int(point, ControlFlow::Break) { + ControlFlow::Break(node) => Some(node), + ControlFlow::Continue(()) => None, + } + } + + /// Mutable variant of [`locate_at_point_int`][Self::locate_at_point_int]. + pub fn locate_at_point_int_mut( + &mut self, + point: &::Point, + ) -> Option<&mut T> { + match self.locate_all_at_point_int_mut(point, ControlFlow::Break) { + ControlFlow::Break(node) => Some(node), + ControlFlow::Continue(()) => None, + } + } + + /// Locate all elements containing a given point. + /// + /// Method [PointDistance::contains_point] is used + /// to determine if a tree element contains the given point. + /// # Example + /// ``` + /// use rstar::RTree; + /// use rstar::primitives::Rectangle; + /// + /// let tree = RTree::bulk_load(vec![ + /// Rectangle::from_corners([0.0, 0.0], [2.0, 2.0]), + /// Rectangle::from_corners([1.0, 1.0], [3.0, 3.0]) + /// ]); + /// + /// assert_eq!(tree.locate_all_at_point(&[1.5, 1.5]).count(), 2); + /// assert_eq!(tree.locate_all_at_point(&[0.0, 0.0]).count(), 1); + /// assert_eq!(tree.locate_all_at_point(&[-1., 0.0]).count(), 0); + /// ``` + pub fn locate_all_at_point( + &self, + point: &::Point, + ) -> LocateAllAtPoint { + LocateAllAtPoint::new(&self.root, SelectAtPointFunction::new(point.clone())) + } + + /// Mutable variant of [`locate_all_at_point`][Self::locate_all_at_point]. + pub fn locate_all_at_point_mut( + &mut self, + point: &::Point, + ) -> LocateAllAtPointMut { + LocateAllAtPointMut::new(&mut self.root, SelectAtPointFunction::new(point.clone())) + } + + /// Variant of [`locate_all_at_point`][Self::locate_all_at_point] using internal iteration. + pub fn locate_all_at_point_int<'a, V, B>( + &'a self, + point: &::Point, + mut visitor: V, + ) -> ControlFlow + where + V: FnMut(&'a T) -> ControlFlow, + { + select_nodes( + &self.root, + &SelectAtPointFunction::new(point.clone()), + &mut visitor, + ) + } + + /// Mutable variant of [`locate_all_at_point_int`][Self::locate_all_at_point_int]. + pub fn locate_all_at_point_int_mut<'a, V, B>( + &'a mut self, + point: &::Point, + mut visitor: V, + ) -> ControlFlow + where + V: FnMut(&'a mut T) -> ControlFlow, + { + select_nodes_mut( + &mut self.root, + &SelectAtPointFunction::new(point.clone()), + &mut visitor, + ) + } + + /// Removes an element containing a given point. + /// + /// The removed element, if any, is returned. If multiple elements cover the given point, + /// only one of them is removed and returned. + /// + /// # Example + /// ``` + /// use rstar::RTree; + /// use rstar::primitives::Rectangle; + /// + /// let mut tree = RTree::bulk_load(vec![ + /// Rectangle::from_corners([0.0, 0.0], [2.0, 2.0]), + /// Rectangle::from_corners([1.0, 1.0], [3.0, 3.0]) + /// ]); + /// + /// assert!(tree.remove_at_point(&[1.5, 1.5]).is_some()); + /// assert!(tree.remove_at_point(&[1.5, 1.5]).is_some()); + /// assert!(tree.remove_at_point(&[1.5, 1.5]).is_none()); + ///``` + pub fn remove_at_point(&mut self, point: &::Point) -> Option { + let removal_function = SelectAtPointFunction::new(point.clone()); + self.remove_with_selection_function(removal_function) + } +} + +impl RTree +where + Params: RTreeParams, + T: RTreeObject + PartialEq, +{ + /// Returns `true` if a given element is equal (`==`) to an element in the + /// r-tree. + /// + /// This method will only work correctly if two equal elements also have the + /// same envelope. + /// + /// # Example + /// ``` + /// use rstar::RTree; + /// + /// let mut tree = RTree::new(); + /// assert!(!tree.contains(&[0.0, 2.0])); + /// tree.insert([0.0, 2.0]); + /// assert!(tree.contains(&[0.0, 2.0])); + /// ``` + pub fn contains(&self, t: &T) -> bool { + self.locate_in_envelope(&t.envelope()).any(|e| e == t) + } + + /// Removes and returns an element of the r-tree equal (`==`) to a given element. + /// + /// If multiple elements equal to the given elements are contained in the tree, only + /// one of them is removed and returned. + /// + /// This method will only work correctly if two equal elements also have the + /// same envelope. + /// + /// # Example + /// ``` + /// use rstar::RTree; + /// + /// let mut tree = RTree::new(); + /// tree.insert([0.0, 2.0]); + /// // The element can be inserted twice just fine + /// tree.insert([0.0, 2.0]); + /// assert!(tree.remove(&[0.0, 2.0]).is_some()); + /// assert!(tree.remove(&[0.0, 2.0]).is_some()); + /// assert!(tree.remove(&[0.0, 2.0]).is_none()); + /// ``` + pub fn remove(&mut self, t: &T) -> Option { + let removal_function = SelectEqualsFunction::new(t); + self.remove_with_selection_function(removal_function) + } +} + +impl RTree +where + Params: RTreeParams, + T: PointDistance, +{ + /// Returns the nearest neighbor for a given point. + /// + /// The distance is calculated by calling + /// [PointDistance::distance_2] + /// + /// # Example + /// ``` + /// use rstar::RTree; + /// let tree = RTree::bulk_load(vec![ + /// [0.0, 0.0], + /// [0.0, 1.0], + /// ]); + /// assert_eq!(tree.nearest_neighbor(&[-1., 0.0]), Some(&[0.0, 0.0])); + /// assert_eq!(tree.nearest_neighbor(&[0.0, 2.0]), Some(&[0.0, 1.0])); + /// ``` + pub fn nearest_neighbor(&self, query_point: &::Point) -> Option<&T> { + if self.size > 0 { + // The single-nearest-neighbor retrieval may in rare cases return None due to + // rounding issues. The iterator will still work, though. + nearest_neighbor::nearest_neighbor(&self.root, query_point.clone()) + .or_else(|| self.nearest_neighbor_iter(query_point).next()) + } else { + None + } + } + + /// Returns the nearest neighbors for a given point. + /// + /// The distance is calculated by calling + /// [PointDistance::distance_2] + /// + /// All returned values will have the exact same distance from the given query point. + /// Returns an empty `Vec` if the tree is empty. + /// + /// # Example + /// ``` + /// use rstar::RTree; + /// let tree = RTree::bulk_load(vec![ + /// [0.0, 0.0], + /// [0.0, 1.0], + /// [1.0, 0.0], + /// ]); + /// + /// // A single nearest neighbor + /// assert_eq!(tree.nearest_neighbors(&[0.01, 0.01]), &[&[0.0, 0.0]]); + /// + /// // Two nearest neighbors + /// let nearest_two = tree.nearest_neighbors(&[1.0, 1.0]); + /// assert_eq!(nearest_two.len(), 2); + /// assert!(nearest_two.contains(&&[0.0, 1.0])); + /// assert!(nearest_two.contains(&&[1.0, 0.0])); + /// ``` + pub fn nearest_neighbors(&self, query_point: &::Point) -> Vec<&T> { + nearest_neighbor::nearest_neighbors(&self.root, query_point.clone()) + } + + /// Returns all elements of the tree within a certain distance. + /// + /// The elements may be returned in any order. Each returned element + /// will have a squared distance less or equal to the given squared distance. + /// + /// This method makes use of [PointDistance::distance_2_if_less_or_equal]. + /// If performance is critical and the distance calculation to the object is fast, + /// overwriting this function may be beneficial. + pub fn locate_within_distance( + &self, + query_point: ::Point, + max_squared_radius: <::Point as Point>::Scalar, + ) -> LocateWithinDistanceIterator { + let selection_function = SelectWithinDistanceFunction::new(query_point, max_squared_radius); + LocateWithinDistanceIterator::new(self.root(), selection_function) + } + + /// Drain all elements of the tree within a certain distance. + /// + /// Similar to [`RTree::locate_within_distance`], but removes and + /// returns the elements via an iterator. + pub fn drain_within_distance( + &mut self, + query_point: ::Point, + max_squared_radius: <::Point as Point>::Scalar, + ) -> DrainIterator, Params> { + let selection_function = SelectWithinDistanceFunction::new(query_point, max_squared_radius); + self.drain_with_selection_function(selection_function) + } + + /// Returns all elements of the tree sorted by their distance to a given point. + /// + /// # Runtime + /// Every `next()` call runs in `O(log(n))`. Creating the iterator runs in + /// `O(log(n))`. + /// The [r-tree documentation](RTree) contains more information about + /// r-tree performance. + /// + /// # Example + /// ``` + /// use rstar::RTree; + /// let tree = RTree::bulk_load(vec![ + /// [0.0, 0.0], + /// [0.0, 1.0], + /// ]); + /// + /// let nearest_neighbors = tree.nearest_neighbor_iter(&[0.5, 0.0]).collect::>(); + /// assert_eq!(nearest_neighbors, vec![&[0.0, 0.0], &[0.0, 1.0]]); + /// ``` + pub fn nearest_neighbor_iter( + &self, + query_point: &::Point, + ) -> NearestNeighborIterator { + nearest_neighbor::NearestNeighborIterator::new(&self.root, query_point.clone()) + } + + /// Returns `(element, distance^2)` tuples of the tree sorted by their distance to a given point. + /// + /// The distance is calculated by calling + /// [PointDistance::distance_2]. + #[deprecated(note = "Please use nearest_neighbor_iter_with_distance_2 instead")] + pub fn nearest_neighbor_iter_with_distance( + &self, + query_point: &::Point, + ) -> NearestNeighborDistance2Iterator { + nearest_neighbor::NearestNeighborDistance2Iterator::new(&self.root, query_point.clone()) + } + + /// Returns `(element, distance^2)` tuples of the tree sorted by their distance to a given point. + /// + /// The distance is calculated by calling + /// [PointDistance::distance_2]. + pub fn nearest_neighbor_iter_with_distance_2( + &self, + query_point: &::Point, + ) -> NearestNeighborDistance2Iterator { + nearest_neighbor::NearestNeighborDistance2Iterator::new(&self.root, query_point.clone()) + } + + /// Removes the nearest neighbor for a given point and returns it. + /// + /// The distance is calculated by calling + /// [PointDistance::distance_2]. + /// + /// # Example + /// ``` + /// use rstar::RTree; + /// let mut tree = RTree::bulk_load(vec![ + /// [0.0, 0.0], + /// [0.0, 1.0], + /// ]); + /// assert_eq!(tree.pop_nearest_neighbor(&[0.0, 0.0]), Some([0.0, 0.0])); + /// assert_eq!(tree.pop_nearest_neighbor(&[0.0, 0.0]), Some([0.0, 1.0])); + /// assert_eq!(tree.pop_nearest_neighbor(&[0.0, 0.0]), None); + /// ``` + pub fn pop_nearest_neighbor( + &mut self, + query_point: &::Point, + ) -> Option { + if let Some(neighbor) = self.nearest_neighbor(query_point) { + let removal_function = SelectByAddressFunction::new(neighbor.envelope(), neighbor); + self.remove_with_selection_function(removal_function) + } else { + None + } + } +} + +impl RTree +where + T: RTreeObject, + Params: RTreeParams, +{ + /// Inserts a new element into the r-tree. + /// + /// If the element is already present in the tree, it will now be present twice. + /// + /// # Runtime + /// This method runs in `O(log(n))`. + /// The [r-tree documentation](RTree) contains more information about + /// r-tree performance. + pub fn insert(&mut self, t: T) { + Params::DefaultInsertionStrategy::insert(self, t); + self.size += 1; + } +} + +impl IntoIterator for RTree +where + T: RTreeObject, + Params: RTreeParams, +{ + type IntoIter = IntoIter; + type Item = T; + + fn into_iter(self) -> Self::IntoIter { + IntoIter::new(self.root) + } +} + +impl<'a, T, Params> IntoIterator for &'a RTree +where + T: RTreeObject, + Params: RTreeParams, +{ + type IntoIter = RTreeIterator<'a, T>; + type Item = &'a T; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, T, Params> IntoIterator for &'a mut RTree +where + T: RTreeObject, + Params: RTreeParams, +{ + type IntoIter = RTreeIteratorMut<'a, T>; + type Item = &'a mut T; + + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +#[cfg(test)] +mod test { + use super::RTree; + use crate::algorithm::rstar::RStarInsertionStrategy; + use crate::params::RTreeParams; + 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 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); + 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(); + assert_eq!(tree.size(), 0); + } + + #[test] + fn test_insert_single() { + let mut tree: RTree<_> = RTree::new(); + tree.insert([0.02f32, 0.4f32]); + assert_eq!(tree.size(), 1); + assert!(tree.contains(&[0.02, 0.4])); + assert!(!tree.contains(&[0.3, 0.2])); + } + + #[test] + fn test_insert_many() { + const NUM_POINTS: usize = 1000; + let points = create_random_points(NUM_POINTS, SEED_1); + let mut tree = RTree::new(); + for p in &points { + tree.insert(*p); + tree.root.sanity_check::(true); + } + assert_eq!(tree.size(), NUM_POINTS); + for p in &points { + assert!(tree.contains(p)); + } + } + + #[test] + fn test_fmt_debug() { + let tree = RTree::bulk_load(vec![[0, 1], [0, 1]]); + let debug: String = format!("{:?}", tree); + assert_eq!(debug, "RTree { size: 2, items: {[0, 1], [0, 1]} }"); + } + + #[test] + fn test_default() { + let tree: RTree<[f32; 2]> = Default::default(); + assert_eq!(tree.size(), 0); + } + + #[cfg(feature = "serde")] + #[test] + fn test_serialization() { + use crate::test_utilities::create_random_integers; + + use serde_json; + const SIZE: usize = 20; + let points = create_random_integers::<[i32; 2]>(SIZE, SEED_1); + let tree = RTree::bulk_load(points.clone()); + let json = serde_json::to_string(&tree).expect("Serializing tree failed"); + let parsed: RTree<[i32; 2]> = + serde_json::from_str(&json).expect("Deserializing tree failed"); + assert_eq!(parsed.size(), SIZE); + for point in &points { + assert!(parsed.contains(point)); + } + } + + #[test] + fn test_bulk_load_crash() { + let bulk_nodes = vec![ + [570.0, 1080.0, 89.0], + [30.0, 1080.0, 627.0], + [1916.0, 1080.0, 68.0], + [274.0, 1080.0, 790.0], + [476.0, 1080.0, 895.0], + [1557.0, 1080.0, 250.0], + [1546.0, 1080.0, 883.0], + [1512.0, 1080.0, 610.0], + [1729.0, 1080.0, 358.0], + [1841.0, 1080.0, 434.0], + [1752.0, 1080.0, 696.0], + [1674.0, 1080.0, 705.0], + [136.0, 1080.0, 22.0], + [1593.0, 1080.0, 71.0], + [586.0, 1080.0, 272.0], + [348.0, 1080.0, 373.0], + [502.0, 1080.0, 2.0], + [1488.0, 1080.0, 1072.0], + [31.0, 1080.0, 526.0], + [1695.0, 1080.0, 559.0], + [1663.0, 1080.0, 298.0], + [316.0, 1080.0, 417.0], + [1348.0, 1080.0, 731.0], + [784.0, 1080.0, 126.0], + [225.0, 1080.0, 847.0], + [79.0, 1080.0, 819.0], + [320.0, 1080.0, 504.0], + [1714.0, 1080.0, 1026.0], + [264.0, 1080.0, 229.0], + [108.0, 1080.0, 158.0], + [1665.0, 1080.0, 604.0], + [496.0, 1080.0, 231.0], + [1813.0, 1080.0, 865.0], + [1200.0, 1080.0, 326.0], + [1661.0, 1080.0, 818.0], + [135.0, 1080.0, 229.0], + [424.0, 1080.0, 1016.0], + [1708.0, 1080.0, 791.0], + [1626.0, 1080.0, 682.0], + [442.0, 1080.0, 895.0], + ]; + + let nodes = vec![ + [1916.0, 1060.0, 68.0], + [1664.0, 1060.0, 298.0], + [1594.0, 1060.0, 71.0], + [225.0, 1060.0, 846.0], + [1841.0, 1060.0, 434.0], + [502.0, 1060.0, 2.0], + [1625.5852, 1060.0122, 682.0], + [1348.5273, 1060.0029, 731.08124], + [316.36127, 1060.0298, 418.24515], + [1729.3253, 1060.0023, 358.50134], + ]; + let mut tree = RTree::bulk_load(bulk_nodes); + for node in nodes { + // Bulk loading will create nodes larger than Params::MAX_SIZE, + // which is intentional and not harmful. + tree.insert(node); + tree.root().sanity_check::(false); + } + } +} diff --git a/thirdparty/rstar/src/test_utilities.rs b/thirdparty/rstar/src/test_utilities.rs new file mode 100644 index 0000000..df5e4e9 --- /dev/null +++ b/thirdparty/rstar/src/test_utilities.rs @@ -0,0 +1,51 @@ +use crate::primitives::*; +use crate::{Point, RTreeObject}; +use rand::distributions::Uniform; +use rand::{Rng, SeedableRng}; +use rand_hc::Hc128Rng; + +pub type Seed = [u8; 32]; + +pub const SEED_1: &Seed = b"wPYxAkIiHcEmSBAxQFoXFrpYToCe1B71"; +pub const SEED_2: &Seed = b"4KbTVjPT4DXSwWAsQM5dkWWywPKZRfCX"; + +pub fn create_random_integers>(num_points: usize, seed: &Seed) -> Vec

{ + let mut result = Vec::with_capacity(num_points); + let mut rng = Hc128Rng::from_seed(*seed); + let range = Uniform::from(-100_000..100_000); + + for _ in 0..num_points { + let p = Point::generate(|_| rng.sample(range)); + result.push(p); + } + result +} + +pub fn create_random_points(num_points: usize, seed: &Seed) -> Vec<[f64; 2]> { + let mut result = Vec::with_capacity(num_points); + let mut rng = Hc128Rng::from_seed(*seed); + for _ in 0..num_points { + result.push(rng.gen()); + } + result +} + +pub fn create_random_lines(num_lines: usize, seed: &Seed) -> Vec> { + let mut result = Vec::with_capacity(num_lines); + let mut rng = Hc128Rng::from_seed(*seed); + let factor = 10. / num_lines as f64; + for _ in 0..num_lines { + let point: [f64; 2] = rng.gen(); + let offset: [f64; 2] = rng.gen(); + result.push(Line::new( + point, + [point[0] + offset[1] * factor, point[1] + offset[1] * factor], + )); + } + result +} + +pub fn create_random_rectangles(num_rectangles: usize, seed: &Seed) -> Vec> { + let lines = create_random_lines(num_rectangles, seed); + lines.iter().map(|line| line.envelope().into()).collect() +} From 29076cb3cf8641ccb1a96dee1781bca92e5a1923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Mockers?= Date: Fri, 27 Mar 2026 04:16:12 +0100 Subject: [PATCH 3/7] rename --- Cargo.toml | 4 ++-- src/layers.rs | 4 ++-- src/lib.rs | 6 +++--- thirdparty/rstar/Cargo.toml | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0f8e5b6..47be2fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ verbose = [] async = [] no-default-baking = [] detailed-layers = [] -serde = ["glam/serde", "rstar/serde", "dep:serde", "rerecast/serialize"] +serde = ["glam/serde", "rstar2/serde", "dep:serde", "rerecast/serialize"] recast = [] [dependencies] @@ -27,7 +27,7 @@ tracing = { version = "0.1", optional = true } hashbrown = { version = "0.16" } glam = { version = "0.30.8", features = ["approx"] } smallvec = { version = "1.15", features = ["union", "const_generics"] } -rstar = { version = "0.12", path = "thirdparty/rstar" } +rstar2 = { version = "0.12", path = "thirdparty/rstar" } serde = { version = "1.0", features = ["derive"], optional = true } geo = "0.32.0" log = "0.4" diff --git a/src/layers.rs b/src/layers.rs index 8b934b3..2c9201a 100644 --- a/src/layers.rs +++ b/src/layers.rs @@ -2,7 +2,7 @@ use tracing::instrument; use glam::{vec2, Vec2}; -use rstar::RTree; +use rstar2::RTree; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -180,7 +180,7 @@ impl Layer { self.baked_polygons .as_ref() .unwrap() - .locate_in_envelope_intersecting(&rstar::AABB::from_point(query_point)) + .locate_in_envelope_intersecting(&rstar2::AABB::from_point(query_point)) .filter_map(|bp| { self.point_in_polygon(*point, &self.polygons[bp.index]) .then_some(bp.index as u32) diff --git a/src/lib.rs b/src/lib.rs index 5a98758..0a7f02d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -322,11 +322,11 @@ struct BoundedPolygon { aabb_max: [f32; 2], } -impl rstar::RTreeObject for BoundedPolygon { - type Envelope = rstar::AABB<[f32; 2]>; +impl rstar2::RTreeObject for BoundedPolygon { + type Envelope = rstar2::AABB<[f32; 2]>; fn envelope(&self) -> Self::Envelope { - rstar::AABB::from_sorted(self.aabb_min, self.aabb_max) + rstar2::AABB::from_sorted(self.aabb_min, self.aabb_max) } } diff --git a/thirdparty/rstar/Cargo.toml b/thirdparty/rstar/Cargo.toml index 42a2678..5925316 100644 --- a/thirdparty/rstar/Cargo.toml +++ b/thirdparty/rstar/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2018" rust-version = "1.63" -name = "rstar" +name = "rstar2" version = "0.12.2" authors = [ "Stefan Altmayer ", @@ -42,7 +42,7 @@ license = "MIT OR Apache-2.0" repository = "https://github.com/georust/rstar" [lib] -name = "rstar" +name = "rstar2" path = "src/lib.rs" [dependencies.heapless] From 2350eb45d2fe3ec38657aebbc11976c0c91e065b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Mockers?= Date: Fri, 27 Mar 2026 19:23:37 +0100 Subject: [PATCH 4/7] use forked rstar --- Cargo.toml | 4 +- src/layers.rs | 4 +- src/lib.rs | 6 +- thirdparty/rstar/.cargo-checksum.json | 1 - thirdparty/rstar/.cargo_vcs_info.json | 6 - thirdparty/rstar/CHANGELOG.md | 126 -- thirdparty/rstar/Cargo.toml | 93 -- thirdparty/rstar/Cargo.toml.orig | 34 - thirdparty/rstar/README.md | 77 -- thirdparty/rstar/src/aabb.rs | 280 ---- .../bulk_load/bulk_load_sequential.rs | 149 --- .../bulk_load/cluster_group_iterator.rs | 99 -- .../rstar/src/algorithm/bulk_load/mod.rs | 4 - .../src/algorithm/intersection_iterator.rs | 156 --- thirdparty/rstar/src/algorithm/iterators.rs | 419 ------ thirdparty/rstar/src/algorithm/mod.rs | 8 - .../rstar/src/algorithm/nearest_neighbor.rs | 405 ------ thirdparty/rstar/src/algorithm/removal.rs | 397 ------ thirdparty/rstar/src/algorithm/rstar.rs | 354 ----- .../src/algorithm/selection_functions.rs | 241 ---- thirdparty/rstar/src/envelope.rs | 72 - thirdparty/rstar/src/lib.rs | 64 - thirdparty/rstar/src/mint.rs | 94 -- thirdparty/rstar/src/node.rs | 168 --- thirdparty/rstar/src/object.rs | 233 ---- thirdparty/rstar/src/params.rs | 116 -- thirdparty/rstar/src/point.rs | 437 ------ .../rstar/src/primitives/cached_envelope.rs | 127 -- .../rstar/src/primitives/geom_with_data.rs | 136 -- thirdparty/rstar/src/primitives/line.rs | 142 -- thirdparty/rstar/src/primitives/mod.rs | 15 - thirdparty/rstar/src/primitives/object_ref.rs | 62 - .../rstar/src/primitives/point_with_data.rs | 72 - thirdparty/rstar/src/primitives/rectangle.rs | 134 -- thirdparty/rstar/src/rtree.rs | 1167 ----------------- thirdparty/rstar/src/test_utilities.rs | 51 - 36 files changed, 7 insertions(+), 5946 deletions(-) delete mode 100644 thirdparty/rstar/.cargo-checksum.json delete mode 100644 thirdparty/rstar/.cargo_vcs_info.json delete mode 100644 thirdparty/rstar/CHANGELOG.md delete mode 100644 thirdparty/rstar/Cargo.toml delete mode 100644 thirdparty/rstar/Cargo.toml.orig delete mode 100644 thirdparty/rstar/README.md delete mode 100644 thirdparty/rstar/src/aabb.rs delete mode 100644 thirdparty/rstar/src/algorithm/bulk_load/bulk_load_sequential.rs delete mode 100644 thirdparty/rstar/src/algorithm/bulk_load/cluster_group_iterator.rs delete mode 100644 thirdparty/rstar/src/algorithm/bulk_load/mod.rs delete mode 100644 thirdparty/rstar/src/algorithm/intersection_iterator.rs delete mode 100644 thirdparty/rstar/src/algorithm/iterators.rs delete mode 100644 thirdparty/rstar/src/algorithm/mod.rs delete mode 100644 thirdparty/rstar/src/algorithm/nearest_neighbor.rs delete mode 100644 thirdparty/rstar/src/algorithm/removal.rs delete mode 100644 thirdparty/rstar/src/algorithm/rstar.rs delete mode 100644 thirdparty/rstar/src/algorithm/selection_functions.rs delete mode 100644 thirdparty/rstar/src/envelope.rs delete mode 100644 thirdparty/rstar/src/lib.rs delete mode 100644 thirdparty/rstar/src/mint.rs delete mode 100644 thirdparty/rstar/src/node.rs delete mode 100644 thirdparty/rstar/src/object.rs delete mode 100644 thirdparty/rstar/src/params.rs delete mode 100644 thirdparty/rstar/src/point.rs delete mode 100644 thirdparty/rstar/src/primitives/cached_envelope.rs delete mode 100644 thirdparty/rstar/src/primitives/geom_with_data.rs delete mode 100644 thirdparty/rstar/src/primitives/line.rs delete mode 100644 thirdparty/rstar/src/primitives/mod.rs delete mode 100644 thirdparty/rstar/src/primitives/object_ref.rs delete mode 100644 thirdparty/rstar/src/primitives/point_with_data.rs delete mode 100644 thirdparty/rstar/src/primitives/rectangle.rs delete mode 100644 thirdparty/rstar/src/rtree.rs delete mode 100644 thirdparty/rstar/src/test_utilities.rs diff --git a/Cargo.toml b/Cargo.toml index 47be2fe..e191f1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ verbose = [] async = [] no-default-baking = [] detailed-layers = [] -serde = ["glam/serde", "rstar2/serde", "dep:serde", "rerecast/serialize"] +serde = ["glam/serde", "rstar/serde", "dep:serde", "rerecast/serialize"] recast = [] [dependencies] @@ -27,7 +27,7 @@ tracing = { version = "0.1", optional = true } hashbrown = { version = "0.16" } glam = { version = "0.30.8", features = ["approx"] } smallvec = { version = "1.15", features = ["union", "const_generics"] } -rstar2 = { version = "0.12", path = "thirdparty/rstar" } +rstar = { version = "0.12", git = "https://github.com/mockersf/rstar", branch = "AABB-from-known-bounds" } serde = { version = "1.0", features = ["derive"], optional = true } geo = "0.32.0" log = "0.4" diff --git a/src/layers.rs b/src/layers.rs index 2c9201a..01702bb 100644 --- a/src/layers.rs +++ b/src/layers.rs @@ -2,7 +2,7 @@ use tracing::instrument; use glam::{vec2, Vec2}; -use rstar2::RTree; +use rstar::RTree; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -180,7 +180,7 @@ impl Layer { self.baked_polygons .as_ref() .unwrap() - .locate_in_envelope_intersecting(&rstar2::AABB::from_point(query_point)) + .locate_in_envelope_intersecting(rstar::AABB::from_point(query_point)) .filter_map(|bp| { self.point_in_polygon(*point, &self.polygons[bp.index]) .then_some(bp.index as u32) diff --git a/src/lib.rs b/src/lib.rs index 0a7f02d..075bf7f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -322,11 +322,11 @@ struct BoundedPolygon { aabb_max: [f32; 2], } -impl rstar2::RTreeObject for BoundedPolygon { - type Envelope = rstar2::AABB<[f32; 2]>; +impl rstar::RTreeObject for BoundedPolygon { + type Envelope = rstar::AABB<[f32; 2]>; fn envelope(&self) -> Self::Envelope { - rstar2::AABB::from_sorted(self.aabb_min, self.aabb_max) + rstar::AABB::from_bounds(self.aabb_min, self.aabb_max) } } diff --git a/thirdparty/rstar/.cargo-checksum.json b/thirdparty/rstar/.cargo-checksum.json deleted file mode 100644 index a25b60d..0000000 --- a/thirdparty/rstar/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{".cargo_vcs_info.json":"c5544a43d973aa7f53ae32efe80a36cc68ebb6a3c512afc9324a61b6c9b41044","CHANGELOG.md":"5424e21bcea1be22cecd68185e83288cd43f9ce28a2115d394225ec4da0f2d0b","Cargo.toml":"025bb74e428ccebfe3598b18318ec1183720521810250b83e9895e13484c591f","Cargo.toml.orig":"5fcc9507370e3cc11bb34406c7469b39662cb4a851d7cb098bacac234692cc53","README.md":"35badde6b30495407f9ac995fbac367ed454edbdc5fa1b0151dd05dd77347f3b","src/aabb.rs":"5f2ebfaa9f6af57c09db519debe0b133972078df1cd43e6677fefecbb822e4b1","src/algorithm/bulk_load/bulk_load_sequential.rs":"101f7fe86b01d82373bff72d9528a02cfa0215c21f63a1c894709bb7e7bf168a","src/algorithm/bulk_load/cluster_group_iterator.rs":"0518678a4d5a1a2bb1f9deecc677904f6890f67abcb2ca8ce10f3a13e1a56719","src/algorithm/bulk_load/mod.rs":"f6f3f015ea2d6c8b0342616bb993f6be35f40836795daabac6b2eb2d354e57b3","src/algorithm/intersection_iterator.rs":"9b939ad49d9c678c1af2d54058638158f0d5c0faa1baff2e3ed3b67b7104a581","src/algorithm/iterators.rs":"0d830b691ba7265028ae7b4251d04dc59192a43ddb62da17e58eae6abd4aa13e","src/algorithm/mod.rs":"4085dd753a5f7c779a80dcad72098f26aa3ba6701292a766572b605c4e86a192","src/algorithm/nearest_neighbor.rs":"d4a3b147c21b69da2373f33f4ebb4d0d11322649122c46708a7937aab68e2138","src/algorithm/removal.rs":"174cb3d9d8b965f07b537408e6bc82833dd303ab6ff3a10c325f0773ea46b10d","src/algorithm/rstar.rs":"1bdb4218da229627181aa469627819018f88e6c6efe8ab1fadb520a2dbf83e40","src/algorithm/selection_functions.rs":"6ce0395ae821e09ed1d4325f43fec48b47b56ae3b861e1aa02769cb669a275f9","src/envelope.rs":"9b8800ce33701f14331e791c04f8a9192856e514ea2fd6f8c5890dbca682fa4b","src/lib.rs":"50d187e5b3e0edb373a31a74bbe7a4fe0072b2541d684ecf7fb7a247020cf4ff","src/mint.rs":"522ca5e07b5510b73bb60a70d8022e7ff48a7ed6f94ac797034aeb81e6760266","src/node.rs":"b5577b72072c0ef4776665de84007a177f7a249ad055964a691baa7d81350d34","src/object.rs":"dfd93bca931fdb61bb0fd0e320552843a3f79d6829e70423e47053015b18b81c","src/params.rs":"4f45e7dc147e0fccb46ed7c8b7c6ef0edbba682ea68c01ce53270cbd81722a4e","src/point.rs":"4908f76d30fa5ae5049a0bbbf26c116e9a8cacc86104ff1bd9b93eca23003d52","src/primitives/cached_envelope.rs":"7524b6261b20bd06e7f670427f61d3c4cbdb7640fe7cff3af4f6f0aa29955569","src/primitives/geom_with_data.rs":"fa5a715a579a09dfc85d2cf7a9d54abb0e01e91f9caee30085d1a3cb82721ed6","src/primitives/line.rs":"59b19c6ee0e3d2da172b43150da68a328b44521f1efe5bedd3ce13d5cd2830c7","src/primitives/mod.rs":"0dff8cd779cc848fd0d993e6a3427cb0fa2a8789bf51814b12a73fdba461f7b9","src/primitives/object_ref.rs":"2c979f2189c21e0310a47e3445ad7a62f1fbf5e042b3f8b06ac511ae41c9fd7a","src/primitives/point_with_data.rs":"8bfd88c5e1a2a466ecc61cc57a3458009cb65f5716547fec83c94fb1f952bb64","src/primitives/rectangle.rs":"fe49dc601a05ea9d339927854977f302955a403c898277fda5b28bdeeeda49f5","src/rtree.rs":"6c2441fc60d411ef07dfb82695173d28742bbfb82962aeca170fc7f0b39c7ff3","src/test_utilities.rs":"28ce88bf0b533332aa53fff49431fbf8e644acac6f30fe657b50b02da76322d9"},"package":"421400d13ccfd26dfa5858199c30a5d76f9c54e0dba7575273025b43c5175dbb"} \ No newline at end of file diff --git a/thirdparty/rstar/.cargo_vcs_info.json b/thirdparty/rstar/.cargo_vcs_info.json deleted file mode 100644 index d62ce33..0000000 --- a/thirdparty/rstar/.cargo_vcs_info.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "git": { - "sha1": "c8c5bf9e41468281d030869d409e3f67f1aaf5b7" - }, - "path_in_vcs": "rstar" -} \ No newline at end of file diff --git a/thirdparty/rstar/CHANGELOG.md b/thirdparty/rstar/CHANGELOG.md deleted file mode 100644 index 27ea20a..0000000 --- a/thirdparty/rstar/CHANGELOG.md +++ /dev/null @@ -1,126 +0,0 @@ -# 0.12.2 - -## Changed -- Reverted the change to `AABB::new_empty` while still avoiding overflow panics applying selections on empty trees ([PR](https://github.com/georust/rstar/pull/184) - -# 0.12.1 **YANKED** - -## Added -- Provide selection methods based on internal iteration ([PR](https://github.com/georust/rstar/pull/164)) -- Add ObjectRef combinator to build tree referencing objects elsewhere ([PR](https://github.com/georust/rstar/pull/178)) - -## Changed -- Switched to unstable sort for envelopes and node reinsertion ([PR](https://github.com/georust/rstar/pull/160)) -- Use a more tame value for `AABB::new_empty` to avoid overflow panics applying selections on empty trees ([PR](https://github.com/georust/rstar/pull/162)) -- Avoid infinite recursion due to numerical instability when computing the number of clusters ([PR](https://github.com/georust/rstar/pull/166)) - - -# 0.12.0 - -## Added -- Add optional support for the [mint](https://docs.rs/mint/0.5.9/mint/index.html) crate -- Implemented `IntoIter` for `RTree`, i.e. added a owning iterator -- Added cached envelope bulk load benchmark -- Implemented `Hash` for `AABB`, `Line`, and `Rectangle`, provided the `Point` used implements `Hash` itself -- Implemented `Default` for `DefaultParams` - -## Changed -- Fixed a stack overflow error in `DrainIterator::next` -- Clarified that the distance measure in `distance_2` is not restricted to euclidean distance -- updated to `heapless=0.8` -- Updated CI config to use merge queue ([PR](https://github.com/georust/rstar/pull/143)) - -# 0.11.0 - -## Added -- Add `CachedEnvelope` combinator which simplifies memoizing envelope computations. ([PR](https://github.com/georust/rstar/pull/118)) -- `Point` is now implemented as const generic for any length of `RTreeNum` array - -## Changed -- Increase our MSRV to Rust 1.63 following that of the `geo` crate. ([PR](https://github.com/georust/rstar/pull/124)) - -# 0.10.0 - -## Added -- Added method `RTree::drain()`. -- Changed license field to [SPDX 2.1 license expression](https://spdx.dev/spdx-specification-21-web-version/#h.jxpfx0ykyb60) - -## Changed -- fixed all clippy lint issues -- Fixed error when setting MIN_SIZE = 1 in `RTreeParams` and added assert for positive MIN_SIZE -- BREAKING: Removed the `Copy` bound from `Point` and `Envelope`. ([PR](https://github.com/georust/rstar/pull/103)) - -# 0.9.3 -## Changed -- Removed dependency on `pdqselect` ([PR](https://github.com/georust/rstar/pull/85)) -- New **minimal supported rust version (MSRV): 1.51.0** -- Replace all usages of `std` with `core` & `alloc` to make `rstar` fit for - `no_std`. ([PR](https://github.com/georust/rstar/pull/83)) -- Updated `heapless` dependency to 0.7 to make use of const generics. ([PR](https://github.com/georust/rstar/pull/87)) - - -# 0.9.2 -- Add `RTree::drain_*` methods to remove and drain selected items. ([PR](https://github.com/georust/rstar/pull/77)) -- Add trait `Point` for tuples containing elements of the same type, up to nine dimensions. -- Pinned `pdqselect` to 0.1.0 as 0.1.1 has switched to the 2021 edition - -## Changed -- Expose all iterator types in `crate::iterators` module ([PR](https://github.com/georust/rstar/pull/77)) - -# 0.9.1 - -## Added -- A generic container for a geometry and associated data: `GeomWithData` ([PR](https://github.com/georust/rstar/pull/74)) - -# 0.9.0 - -## Added -- `RTree::nearest_neighbors` method based on - [spade crate's implementation](https://github.com/Stoeoef/spade) - -## Changed -- Fix floating point inconsistency in `min_max_dist_2` ([PR](https://github.com/georust/rstar/pull/40)). -- BREAKING: `Point::generate` function now accepts a `impl FnMut`. Custom implementations of `Point` must change to - accept `impl FnMut` instead of `impl Fn`. Callers of `Point::generate` should not require changes. -- Update CI images to Stable Rust 1.50 and 1.51 -- Run clippy, rustfmt, update manifest to reflect ownership changes -- Update Criterion and rewrite deprecated benchmark functions -- Remove unused imports -- Remove executable bit from files -- Fix typos, modernize links - -# 0.8.3 -## Changed -- Move crate ownership to the georust organization -## Fixed -- Update dependencies to remove heapless 0.5, which has a known vulnerability - -# 0.8.2 - 2020-08-01 -## Fixed: - - Fixed a rare panic when calling `insert` (See #45) - -# 0.8.1 - 2020-06-18 -## Changed: - - - Fine tuned nearest neighbor iterator inline capacity (see #39). This should boost performance in some cases. - -# 0.8.0 - 2020-05-25 -## Fixed: - - - Bugfix: `RTree::locate_with_selection_function_mut` sometimes returned too many elements for small trees. -## Changed: - - Deprecated `RTree::nearest_neighbor_iter_with_distance`. The name is misleading, use `RTree::nearest_neighbor_iter_with_distance_2` instead. - - Some performance improvements, see #38 and #35 - -## Added - - Added `nearest_neighbor_iter_with_distance_2` #31 - -# 0.7.1 - 2020-01-16 -## Changed: - - `RTree::intersection_candidates_with_other_tree` can now calculate intersections of trees of different item types (see #23) - -# 0.7.0 - 2019-11-25 -## Added: - - `RTree::remove_with_selection_function` - - `RTree::pop_nearest_neighbor` - - Added CHANGELOG.md diff --git a/thirdparty/rstar/Cargo.toml b/thirdparty/rstar/Cargo.toml deleted file mode 100644 index 5925316..0000000 --- a/thirdparty/rstar/Cargo.toml +++ /dev/null @@ -1,93 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2018" -rust-version = "1.63" -name = "rstar2" -version = "0.12.2" -authors = [ - "Stefan Altmayer ", - "The Georust Developers ", -] -build = false -autobins = false -autoexamples = false -autotests = false -autobenches = false -description = "An R*-tree spatial index" -documentation = "https://docs.rs/rstar/" -readme = "README.md" -keywords = [ - "rtree", - "r-tree", - "spatial", - "spatial-index", - "nearest-neighbor", -] -categories = [ - "data-structures", - "algorithms", - "science::geo", -] -license = "MIT OR Apache-2.0" -repository = "https://github.com/georust/rstar" - -[lib] -name = "rstar2" -path = "src/lib.rs" - -[dependencies.heapless] -version = "0.8" - -[dependencies.mint] -version = "0.5.9" -optional = true - -[dependencies.num-traits] -version = "0.2" -features = ["libm"] -default-features = false - -[dependencies.serde] -version = "1.0" -features = [ - "alloc", - "derive", -] -optional = true -default-features = false - -[dependencies.smallvec] -version = "1.6" - -[dev-dependencies.approx] -version = "0.3" - -[dev-dependencies.nalgebra] -version = "0.32.3" -features = ["mint"] - -[dev-dependencies.rand] -version = "0.7" - -[dev-dependencies.rand_hc] -version = "0.2" - -[dev-dependencies.serde_json] -version = "1.0" - -[features] -debug = [] -default = [] - -[badges.maintenance] -status = "actively-developed" diff --git a/thirdparty/rstar/Cargo.toml.orig b/thirdparty/rstar/Cargo.toml.orig deleted file mode 100644 index b8ae9ca..0000000 --- a/thirdparty/rstar/Cargo.toml.orig +++ /dev/null @@ -1,34 +0,0 @@ -[package] -name = "rstar" -version = "0.12.2" -authors = ["Stefan Altmayer ", "The Georust Developers "] -description = "An R*-tree spatial index" -documentation = "https://docs.rs/rstar/" -repository = "https://github.com/georust/rstar" -license = "MIT OR Apache-2.0" -readme = "README.md" -edition = "2018" -rust-version = "1.63" -keywords = ["rtree", "r-tree", "spatial", "spatial-index", "nearest-neighbor"] -categories = ["data-structures", "algorithms", "science::geo"] - -[badges] -maintenance = { status = "actively-developed" } - -[dependencies] -heapless = "0.8" -num-traits = { version = "0.2", default-features = false, features = ["libm"] } -serde = { version = "1.0", optional = true, default-features = false, features = ["alloc", "derive"] } -smallvec = "1.6" -mint = { version = "0.5.9", optional = true } - -[features] -default = [] -debug = [] - -[dev-dependencies] -rand = "0.7" -rand_hc = "0.2" -approx = "0.3" -serde_json = "1.0" -nalgebra = { version = "0.32.3", features = ["mint"] } diff --git a/thirdparty/rstar/README.md b/thirdparty/rstar/README.md deleted file mode 100644 index 763385d..0000000 --- a/thirdparty/rstar/README.md +++ /dev/null @@ -1,77 +0,0 @@ -# rstar - -A flexible, n-dimensional [r*-tree](https://en.wikipedia.org/wiki/R*_tree) implementation for the Rust ecosystem, suitable for use as a spatial index. - -# Features - - A flexible r*-tree written in safe rust - - Supports custom point types - - Supports the insertion of user defined types - - Supported operations: - - Insertion - - Rectangle queries - - Nearest neighbor - - Nearest neighbor iteration - - Locate at point - - Element removal - - Efficient bulk loading - - Features geometric primitives that can readily be inserted into an r-tree: - - Points (arrays with a constant size) - - Lines - - Rectangles - - Small number of dependencies - - Serde support with the `serde` feature - - `no_std` compatible (but requires [`alloc`](https://doc.rust-lang.org/alloc/)) - -## Geometries - -Primitives are provided for point, line, and rectangle geometries. The [`geo`](https://crates.io/crates/geo) crate uses rstar as an efficient spatial index and provides [`RTreeObject`](file:///Users/sth/dev/rstar/target/doc/rstar/trait.RTreeObject.html) implementations for storing complex geometries such as linestrings and polygons. - -# Benchmarks -All benchmarks are performed on a i7-8550U CPU @ 1.80Ghz and with uniformly distributed points. The underlying point type is `[f64; 2]`. - -| Benchmark | Tree size | Time | -|-------------------------------------|-----:|----------:| -| bulk loading | 2000 | 229.82 us | -| sequentially loading | 2000 | 1.4477 ms | -| nearest neighbor (bulk loaded tree) | 100k | 1.32 us | -| nearest neighbor (sequential tree) | 100k | 1.56 us | -| successful point lookup | 100k | 177.32 ns | -| unsuccessful point lookup | 100k | 273.51 ns | - -# Project state -The project is being actively developed, feature requests and PRs are welcome! - -# Documentation -The documentation is hosted on [docs.rs](https://docs.rs/rstar/). - -# Release Checklist - -The crate can be published by the `rstar-publishers` team of -georust. Please follow the steps below while publishing a -new release. - -1. Create branch from master, say `release/`. -2. Ensure `rstar/CHANGELOG.md` describes all the changes - since last release (esp. the breaking ones). -3. Ensure / set `version` metadata in `Cargo.toml` of - `rstar` to the new version. -4. Create PR to master, have it approved and merge. -5. Checkout the updated master, go to `rstar` directory and - run `cargo publish`. -6. Create tag `` and push to `georust/rstar` - -# License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -## Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. diff --git a/thirdparty/rstar/src/aabb.rs b/thirdparty/rstar/src/aabb.rs deleted file mode 100644 index 5bfcf6a..0000000 --- a/thirdparty/rstar/src/aabb.rs +++ /dev/null @@ -1,280 +0,0 @@ -use crate::point::{max_inline, Point, PointExt}; -use crate::{Envelope, RTreeObject}; -use num_traits::{Bounded, One, Zero}; - -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; - -/// An n-dimensional axis aligned bounding box (AABB). -/// -/// An object's AABB is the smallest box totally encompassing an object -/// while being aligned to the current coordinate system. -/// Although these structures are commonly called bounding _boxes_, they exist in any -/// dimension. -/// -/// Note that AABBs cannot be inserted into r-trees. Use the -/// [Rectangle](crate::primitives::Rectangle) struct for this purpose. -/// -/// # Type arguments -/// `P`: The struct is generic over which point type is used. Using an n-dimensional point -/// type will result in an n-dimensional bounding box. -#[derive(Clone, Debug, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct AABB

-where - P: Point, -{ - lower: P, - upper: P, -} - -impl

AABB

-where - P: Point, -{ - /// Returns the AABB encompassing a single point. - pub fn from_point(p: P) -> Self { - AABB { - lower: p.clone(), - upper: p, - } - } - - /// Returns the AABB's lower corner. - /// - /// This is the point contained within the AABB with the smallest coordinate value in each - /// dimension. - pub fn lower(&self) -> P { - self.lower.clone() - } - - /// Returns the AABB's upper corner. - /// - /// This is the point contained within the AABB with the largest coordinate value in each - /// dimension. - pub fn upper(&self) -> P { - self.upper.clone() - } - - /// Creates a new AABB encompassing two points. - pub fn from_corners(p1: P, p2: P) -> Self { - AABB { - lower: p1.min_point(&p2), - upper: p1.max_point(&p2), - } - } - - /// Creates a new AABB from pre-sorted lower and upper bounds. - /// - /// The caller must ensure that `lower` component-wise <= `upper`. - /// No min/max computation is performed. - pub fn from_sorted(lower: P, upper: P) -> Self { - AABB { lower, upper } - } - - /// Creates a new AABB encompassing a collection of points. - pub fn from_points<'a, I>(i: I) -> Self - where - I: IntoIterator + 'a, - P: 'a, - { - i.into_iter().fold( - Self { - lower: P::from_value(P::Scalar::max_value()), - upper: P::from_value(P::Scalar::min_value()), - }, - |aabb, p| Self { - lower: aabb.lower.min_point(p), - upper: aabb.upper.max_point(p), - }, - ) - } - - /// Returns the point within this AABB closest to a given point. - /// - /// If `point` is contained within the AABB, `point` will be returned. - pub fn min_point(&self, point: &P) -> P { - self.upper.min_point(&self.lower.max_point(point)) - } - - /// Returns the squared distance to the AABB's [min_point](AABB::min_point) - pub fn distance_2(&self, point: &P) -> P::Scalar { - if self.contains_point(point) { - Zero::zero() - } else { - self.min_point(point).sub(point).length_2() - } - } -} - -impl

Envelope for AABB

-where - P: Point, -{ - type Point = P; - - fn new_empty() -> Self { - let max = P::Scalar::max_value(); - let min = P::Scalar::min_value(); - Self { - lower: P::from_value(max), - upper: P::from_value(min), - } - } - - fn contains_point(&self, point: &P) -> bool { - self.lower.all_component_wise(point, |x, y| x <= y) - && self.upper.all_component_wise(point, |x, y| x >= y) - } - - fn contains_envelope(&self, other: &Self) -> bool { - self.lower.all_component_wise(&other.lower, |l, r| l <= r) - && self.upper.all_component_wise(&other.upper, |l, r| l >= r) - } - - fn merge(&mut self, other: &Self) { - self.lower = self.lower.min_point(&other.lower); - self.upper = self.upper.max_point(&other.upper); - } - - fn merged(&self, other: &Self) -> Self { - AABB { - lower: self.lower.min_point(&other.lower), - upper: self.upper.max_point(&other.upper), - } - } - - fn intersects(&self, other: &Self) -> bool { - self.lower.all_component_wise(&other.upper, |l, r| l <= r) - && self.upper.all_component_wise(&other.lower, |l, r| l >= r) - } - - fn area(&self) -> P::Scalar { - let zero = P::Scalar::zero(); - let one = P::Scalar::one(); - let diag = self.upper.sub(&self.lower); - diag.fold(one, |acc, cur| max_inline(cur, zero) * acc) - } - - fn distance_2(&self, point: &P) -> P::Scalar { - self.distance_2(point) - } - - fn min_max_dist_2(&self, point: &P) ->

::Scalar { - let l = self.lower.sub(point); - let u = self.upper.sub(point); - let mut max_diff = (Zero::zero(), Zero::zero(), 0); // diff, min, index - let mut result = P::new(); - - for i in 0..P::DIMENSIONS { - let mut min = l.nth(i); - let mut max = u.nth(i); - max = max * max; - min = min * min; - if max < min { - core::mem::swap(&mut min, &mut max); - } - - let diff = max - min; - *result.nth_mut(i) = max; - - if diff >= max_diff.0 { - max_diff = (diff, min, i); - } - } - - *result.nth_mut(max_diff.2) = max_diff.1; - result.fold(Zero::zero(), |acc, curr| acc + curr) - } - - fn center(&self) -> Self::Point { - let one = ::Scalar::one(); - let two = one + one; - self.lower.component_wise(&self.upper, |x, y| (x + y) / two) - } - - fn intersection_area(&self, other: &Self) -> ::Scalar { - AABB { - lower: self.lower.max_point(&other.lower), - upper: self.upper.min_point(&other.upper), - } - .area() - } - - fn perimeter_value(&self) -> P::Scalar { - let diag = self.upper.sub(&self.lower); - let zero = P::Scalar::zero(); - max_inline(diag.fold(zero, |acc, value| acc + value), zero) - } - - fn sort_envelopes>(axis: usize, envelopes: &mut [T]) { - envelopes.sort_unstable_by(|l, r| { - l.envelope() - .lower - .nth(axis) - .partial_cmp(&r.envelope().lower.nth(axis)) - .unwrap() - }); - } - - fn partition_envelopes>( - axis: usize, - envelopes: &mut [T], - selection_size: usize, - ) { - envelopes.select_nth_unstable_by(selection_size, |l, r| { - l.envelope() - .lower - .nth(axis) - .partial_cmp(&r.envelope().lower.nth(axis)) - .unwrap() - }); - } -} - -#[cfg(test)] -mod test { - use super::AABB; - use crate::envelope::Envelope; - use crate::object::PointDistance; - - #[test] - fn empty_rect() { - let empty = AABB::<[f32; 2]>::new_empty(); - - let other = AABB::from_corners([1.0, 1.0], [1.0, 1.0]); - let subject = empty.merged(&other); - assert_eq!(other, subject); - - let other = AABB::from_corners([0.0, 0.0], [0.0, 0.0]); - let subject = empty.merged(&other); - assert_eq!(other, subject); - - let other = AABB::from_corners([0.5, 0.5], [0.5, 0.5]); - let subject = empty.merged(&other); - assert_eq!(other, subject); - - let other = AABB::from_corners([-0.5, -0.5], [-0.5, -0.5]); - let subject = empty.merged(&other); - assert_eq!(other, subject); - } - - /// Test that min_max_dist_2 is identical to distance_2 for the equivalent - /// min max corner of the AABB. This is necessary to prevent optimizations - /// from inadvertently changing floating point order of operations. - #[test] - fn test_min_max_dist_2_issue_40_regression() { - let a = [0.7018702292340033, 0.2121617955083932, 0.8120562975177115]; - let b = [0.7297749764202988, 0.23020869735094462, 0.8194675310336391]; - let aabb = AABB::from_corners(a, b); - let p = [0.6950876013070484, 0.220750082121574, 0.8186032137709887]; - let corner = [a[0], b[1], a[2]]; - assert_eq!(aabb.min_max_dist_2(&p), corner.distance_2(&p)); - } - - #[test] - fn test_from_points_issue_170_regression() { - let aabb = AABB::from_points(&[(3., 3., 3.), (4., 4., 4.)]); - assert_eq!(aabb, AABB::from_corners((3., 3., 3.), (4., 4., 4.))); - } -} diff --git a/thirdparty/rstar/src/algorithm/bulk_load/bulk_load_sequential.rs b/thirdparty/rstar/src/algorithm/bulk_load/bulk_load_sequential.rs deleted file mode 100644 index ca75d8a..0000000 --- a/thirdparty/rstar/src/algorithm/bulk_load/bulk_load_sequential.rs +++ /dev/null @@ -1,149 +0,0 @@ -use crate::envelope::Envelope; -use crate::node::{ParentNode, RTreeNode}; -use crate::object::RTreeObject; -use crate::params::RTreeParams; -use crate::point::Point; - -#[cfg(not(test))] -use alloc::{vec, vec::Vec}; - -#[allow(unused_imports)] // Import is required when building without std -use num_traits::Float; - -use super::cluster_group_iterator::{calculate_number_of_clusters_on_axis, ClusterGroupIterator}; - -fn bulk_load_recursive(elements: Vec) -> ParentNode -where - T: RTreeObject, - ::Point: Point, - Params: RTreeParams, -{ - 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()).max(2); - - let iterator = PartitioningTask::<_, Params> { - number_of_clusters_on_axis, - work_queue: vec![PartitioningState { - current_axis: ::Point::DIMENSIONS, - elements, - }], - _params: Default::default(), - }; - ParentNode::new_parent(iterator.collect()) -} - -/// Represents a partitioning task that still needs to be done. -/// -/// A partitioning iterator will take this item from its work queue and start partitioning "elements" -/// along "current_axis" . -struct PartitioningState { - elements: Vec, - current_axis: usize, -} - -/// Successively partitions the given elements into cluster groups and finally into clusters. -struct PartitioningTask { - work_queue: Vec>, - number_of_clusters_on_axis: usize, - _params: core::marker::PhantomData, -} - -impl Iterator for PartitioningTask { - type Item = RTreeNode; - - fn next(&mut self) -> Option { - while let Some(next) = self.work_queue.pop() { - let PartitioningState { - elements, - current_axis, - } = next; - if current_axis == 0 { - // Partitioning finished successfully on all axis. The remaining cluster forms a new node - let data = bulk_load_recursive::<_, Params>(elements); - return RTreeNode::Parent(data).into(); - } else { - // The cluster group needs to be partitioned further along the next axis - let iterator = ClusterGroupIterator::new( - elements, - self.number_of_clusters_on_axis, - current_axis - 1, - ); - self.work_queue - .extend(iterator.map(|slab| PartitioningState { - elements: slab, - current_axis: current_axis - 1, - })); - } - } - None - } -} - -/// 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(elements: Vec) -> ParentNode -where - T: RTreeObject, - ::Point: Point, - Params: RTreeParams, -{ - bulk_load_recursive::<_, Params>(elements) -} - -#[cfg(test)] -mod test { - use crate::test_utilities::*; - use crate::{Point, RTree, RTreeObject}; - use std::collections::HashSet; - use std::fmt::Debug; - use std::hash::Hash; - - #[test] - fn test_bulk_load_small() { - let random_points = create_random_integers::<[i32; 2]>(50, SEED_1); - create_and_check_bulk_loading_with_points(&random_points); - } - - #[test] - fn test_bulk_load_large() { - let random_points = create_random_integers::<[i32; 2]>(3000, SEED_1); - create_and_check_bulk_loading_with_points(&random_points); - } - - #[test] - fn test_bulk_load_with_different_sizes() { - for size in (0..100).map(|i| i * 7) { - test_bulk_load_with_size_and_dimension::<[i32; 2]>(size); - test_bulk_load_with_size_and_dimension::<[i32; 3]>(size); - test_bulk_load_with_size_and_dimension::<[i32; 4]>(size); - } - } - - fn test_bulk_load_with_size_and_dimension

(size: usize) - where - P: Point + RTreeObject + Send + Sync + Eq + Clone + Debug + Hash + 'static, - P::Envelope: Send + Sync, - { - let random_points = create_random_integers::

(size, SEED_1); - create_and_check_bulk_loading_with_points(&random_points); - } - - fn create_and_check_bulk_loading_with_points

(points: &[P]) - where - P: RTreeObject + Send + Sync + Eq + Clone + Debug + Hash + 'static, - P::Envelope: Send + Sync, - { - let tree = RTree::bulk_load(points.into()); - let set1: HashSet<_> = tree.iter().collect(); - let set2: HashSet<_> = points.iter().collect(); - assert_eq!(set1, set2); - assert_eq!(tree.size(), points.len()); - } -} diff --git a/thirdparty/rstar/src/algorithm/bulk_load/cluster_group_iterator.rs b/thirdparty/rstar/src/algorithm/bulk_load/cluster_group_iterator.rs deleted file mode 100644 index 6200442..0000000 --- a/thirdparty/rstar/src/algorithm/bulk_load/cluster_group_iterator.rs +++ /dev/null @@ -1,99 +0,0 @@ -use crate::{Envelope, Point, RTreeObject, RTreeParams}; - -#[cfg(not(test))] -use alloc::vec::Vec; - -#[allow(unused_imports)] // Import is required when building without std -use num_traits::Float; - -/// Partitions elements into groups of clusters along a specific axis. -pub struct ClusterGroupIterator { - remaining: Vec, - slab_size: usize, - pub cluster_dimension: usize, -} - -impl ClusterGroupIterator { - pub fn new( - elements: Vec, - number_of_clusters_on_axis: usize, - cluster_dimension: usize, - ) -> Self { - let slab_size = div_up(elements.len(), number_of_clusters_on_axis); - ClusterGroupIterator { - remaining: elements, - slab_size, - cluster_dimension, - } - } -} - -impl Iterator for ClusterGroupIterator { - type Item = Vec; - - fn next(&mut self) -> Option { - match self.remaining.len() { - 0 => None, - len if len <= self.slab_size => ::core::mem::take(&mut self.remaining).into(), - _ => { - let slab_axis = self.cluster_dimension; - T::Envelope::partition_envelopes(slab_axis, &mut self.remaining, self.slab_size); - let off_split = self.remaining.split_off(self.slab_size); - ::core::mem::replace(&mut self.remaining, off_split).into() - } - } - } -} - -/// 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 -where - T: RTreeObject, - Params: RTreeParams, -{ - 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 i32; - // The number of elements each subtree will hold - let n_subtree = max_size.powi(depth - 1); - // How many clusters will this node contain - let number_of_clusters = (number_of_elements as f32 / n_subtree).ceil(); - - let max_dimension = ::Point::DIMENSIONS as f32; - // Try to split all clusters among all dimensions as evenly as possible by taking the nth root. - number_of_clusters.powf(1. / max_dimension).ceil() as usize -} - -fn div_up(dividend: usize, divisor: usize) -> usize { - (dividend + divisor - 1) / divisor -} - -#[cfg(test)] -mod test { - use super::ClusterGroupIterator; - - #[test] - fn test_cluster_group_iterator() { - const SIZE: usize = 374; - const NUMBER_OF_CLUSTERS_ON_AXIS: usize = 5; - let elements: Vec<_> = (0..SIZE as i32).map(|i| [-i, -i]).collect(); - let slab_size = (elements.len()) / NUMBER_OF_CLUSTERS_ON_AXIS + 1; - let slabs: Vec<_> = - ClusterGroupIterator::new(elements, NUMBER_OF_CLUSTERS_ON_AXIS, 0).collect(); - assert_eq!(slabs.len(), NUMBER_OF_CLUSTERS_ON_AXIS); - for slab in &slabs[0..slabs.len() - 1] { - assert_eq!(slab.len(), slab_size); - } - let mut total_size = 0; - let mut max_element_for_last_slab = i32::MIN; - for slab in &slabs { - total_size += slab.len(); - let current_max = slab.iter().max_by_key(|point| point[0]).unwrap(); - assert!(current_max[0] > max_element_for_last_slab); - max_element_for_last_slab = current_max[0]; - } - assert_eq!(total_size, SIZE); - } -} diff --git a/thirdparty/rstar/src/algorithm/bulk_load/mod.rs b/thirdparty/rstar/src/algorithm/bulk_load/mod.rs deleted file mode 100644 index 43adad6..0000000 --- a/thirdparty/rstar/src/algorithm/bulk_load/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -mod bulk_load_sequential; -mod cluster_group_iterator; - -pub use self::bulk_load_sequential::bulk_load_sequential; diff --git a/thirdparty/rstar/src/algorithm/intersection_iterator.rs b/thirdparty/rstar/src/algorithm/intersection_iterator.rs deleted file mode 100644 index 3be3c55..0000000 --- a/thirdparty/rstar/src/algorithm/intersection_iterator.rs +++ /dev/null @@ -1,156 +0,0 @@ -use crate::node::ParentNode; -use crate::Envelope; -use crate::RTreeNode; -use crate::RTreeNode::*; -use crate::RTreeObject; - -#[cfg(not(test))] -use alloc::vec::Vec; -use core::mem::take; - -#[cfg(doc)] -use crate::RTree; - -/// Iterator returned by [`RTree::intersection_candidates_with_other_tree`]. -pub struct IntersectionIterator<'a, T, U = T> -where - T: RTreeObject, - U: RTreeObject, -{ - todo_list: Vec<(&'a RTreeNode, &'a RTreeNode)>, - candidates: Vec<&'a RTreeNode>, -} - -impl<'a, T, U> IntersectionIterator<'a, T, U> -where - T: RTreeObject, - U: RTreeObject, -{ - pub(crate) fn new(root1: &'a ParentNode, root2: &'a ParentNode) -> Self { - let mut intersections = IntersectionIterator { - todo_list: Vec::new(), - candidates: Vec::new(), - }; - intersections.add_intersecting_children(root1, root2); - intersections - } - - fn push_if_intersecting(&mut self, node1: &'a RTreeNode, node2: &'a RTreeNode) { - if node1.envelope().intersects(&node2.envelope()) { - self.todo_list.push((node1, node2)); - } - } - - fn add_intersecting_children( - &mut self, - parent1: &'a ParentNode, - parent2: &'a ParentNode, - ) { - if !parent1.envelope().intersects(&parent2.envelope()) { - return; - } - let children1 = parent1 - .children() - .iter() - .filter(|c1| c1.envelope().intersects(&parent2.envelope())); - - let mut children2 = take(&mut self.candidates); - children2.extend( - parent2 - .children() - .iter() - .filter(|c2| c2.envelope().intersects(&parent1.envelope())), - ); - - for child1 in children1 { - for child2 in &children2 { - self.push_if_intersecting(child1, child2); - } - } - - children2.clear(); - self.candidates = children2; - } -} - -impl<'a, T, U> Iterator for IntersectionIterator<'a, T, U> -where - T: RTreeObject, - U: RTreeObject, -{ - type Item = (&'a T, &'a U); - - fn next(&mut self) -> Option { - while let Some(next) = self.todo_list.pop() { - match next { - (Leaf(t1), Leaf(t2)) => return Some((t1, t2)), - (leaf @ Leaf(_), Parent(p)) => { - p.children() - .iter() - .for_each(|c| self.push_if_intersecting(leaf, c)); - } - (Parent(p), leaf @ Leaf(_)) => { - p.children() - .iter() - .for_each(|c| self.push_if_intersecting(c, leaf)); - } - (Parent(p1), Parent(p2)) => { - self.add_intersecting_children(p1, p2); - } - } - } - None - } -} - -#[cfg(test)] -mod test { - use crate::test_utilities::*; - use crate::{Envelope, RTree, RTreeObject}; - - #[test] - fn test_intersection_between_trees() { - let rectangles1 = create_random_rectangles(100, SEED_1); - let rectangles2 = create_random_rectangles(42, SEED_2); - - let mut intersections_brute_force = Vec::new(); - for rectangle1 in &rectangles1 { - for rectangle2 in &rectangles2 { - if rectangle1.envelope().intersects(&rectangle2.envelope()) { - intersections_brute_force.push((rectangle1, rectangle2)); - } - } - } - - let tree1 = RTree::bulk_load(rectangles1.clone()); - let tree2 = RTree::bulk_load(rectangles2.clone()); - let mut intersections_from_trees = tree1 - .intersection_candidates_with_other_tree(&tree2) - .collect::>(); - - intersections_brute_force.sort_by(|a, b| a.partial_cmp(b).unwrap()); - intersections_from_trees.sort_by(|a, b| a.partial_cmp(b).unwrap()); - assert_eq!(intersections_brute_force, intersections_from_trees); - } - - #[test] - fn test_trivial_intersections() { - let points1 = create_random_points(1000, SEED_1); - let points2 = create_random_points(2000, SEED_2); - let tree1 = RTree::bulk_load(points1); - let tree2 = RTree::bulk_load(points2); - - assert_eq!( - tree1 - .intersection_candidates_with_other_tree(&tree2) - .count(), - 0 - ); - assert_eq!( - tree1 - .intersection_candidates_with_other_tree(&tree1) - .count(), - tree1.size() - ); - } -} diff --git a/thirdparty/rstar/src/algorithm/iterators.rs b/thirdparty/rstar/src/algorithm/iterators.rs deleted file mode 100644 index 0000289..0000000 --- a/thirdparty/rstar/src/algorithm/iterators.rs +++ /dev/null @@ -1,419 +0,0 @@ -use crate::algorithm::selection_functions::*; -use crate::node::{ParentNode, RTreeNode}; -use crate::object::RTreeObject; -use core::ops::ControlFlow; - -#[cfg(doc)] -use crate::RTree; - -use smallvec::SmallVec; - -pub use super::intersection_iterator::IntersectionIterator; -pub use super::removal::{DrainIterator, IntoIter}; - -/// Iterator returned by [`RTree::locate_all_at_point`]. -pub type LocateAllAtPoint<'a, T> = SelectionIterator<'a, T, SelectAtPointFunction>; -/// Iterator returned by [`RTree::locate_all_at_point_mut`]. -pub type LocateAllAtPointMut<'a, T> = SelectionIteratorMut<'a, T, SelectAtPointFunction>; - -/// Iterator returned by [`RTree::locate_in_envelope`]. -pub type LocateInEnvelope<'a, T> = SelectionIterator<'a, T, SelectInEnvelopeFunction>; -/// Iterator returned by [`RTree::locate_in_envelope_mut`]. -pub type LocateInEnvelopeMut<'a, T> = SelectionIteratorMut<'a, T, SelectInEnvelopeFunction>; - -/// Iterator returned by [`RTree::locate_in_envelope_intersecting`]. -pub type LocateInEnvelopeIntersecting<'a, T> = - SelectionIterator<'a, T, SelectInEnvelopeFuncIntersecting>; -/// Iterator returned by [`RTree::locate_in_envelope_intersecting_mut`]. -pub type LocateInEnvelopeIntersectingMut<'a, T> = - SelectionIteratorMut<'a, T, SelectInEnvelopeFuncIntersecting>; - -/// Iterator returned by [`RTree::iter`]. -pub type RTreeIterator<'a, T> = SelectionIterator<'a, T, SelectAllFunc>; -/// Iterator returned by [`RTree::iter_mut`]. -pub type RTreeIteratorMut<'a, T> = SelectionIteratorMut<'a, T, SelectAllFunc>; - -/// Iterator returned by [`RTree::locate_within_distance`]. -pub type LocateWithinDistanceIterator<'a, T> = - SelectionIterator<'a, T, SelectWithinDistanceFunction>; - -/// Iterator returned by `RTree::locate_*` methods. -pub struct SelectionIterator<'a, T, Func> -where - T: RTreeObject + 'a, - Func: SelectionFunction, -{ - func: Func, - current_nodes: SmallVec<[&'a RTreeNode; 24]>, -} - -impl<'a, T, Func> SelectionIterator<'a, T, Func> -where - T: RTreeObject, - Func: SelectionFunction, -{ - pub(crate) fn new(root: &'a ParentNode, func: Func) -> Self { - let current_nodes = - if !root.children.is_empty() && func.should_unpack_parent(&root.envelope()) { - root.children.iter().collect() - } else { - SmallVec::new() - }; - - SelectionIterator { - func, - current_nodes, - } - } -} - -impl<'a, T, Func> Iterator for SelectionIterator<'a, T, Func> -where - T: RTreeObject, - Func: SelectionFunction, -{ - type Item = &'a T; - - fn next(&mut self) -> Option<&'a T> { - while let Some(next) = self.current_nodes.pop() { - match next { - RTreeNode::Leaf(ref t) => { - if self.func.should_unpack_leaf(t) { - return Some(t); - } - } - RTreeNode::Parent(ref data) => { - if self.func.should_unpack_parent(&data.envelope) { - self.current_nodes.extend(&data.children); - } - } - } - } - None - } -} - -/// Internal iteration variant of [`SelectionIterator`] -pub fn select_nodes<'a, T, Func, V, B>( - root: &'a ParentNode, - func: &Func, - visitor: &mut V, -) -> ControlFlow -where - T: RTreeObject, - Func: SelectionFunction, - V: FnMut(&'a T) -> ControlFlow, -{ - struct Args<'a, Func, V> { - func: &'a Func, - visitor: &'a mut V, - } - - fn inner<'a, T, Func, V, B>( - parent: &'a ParentNode, - args: &mut Args<'_, Func, V>, - ) -> ControlFlow - where - T: RTreeObject, - Func: SelectionFunction, - V: FnMut(&'a T) -> ControlFlow, - { - for node in parent.children.iter() { - match node { - RTreeNode::Leaf(ref t) => { - if args.func.should_unpack_leaf(t) { - (args.visitor)(t)?; - } - } - RTreeNode::Parent(ref data) => { - if args.func.should_unpack_parent(&data.envelope()) { - inner(data, args)?; - } - } - } - } - - ControlFlow::Continue(()) - } - - if !root.children.is_empty() && func.should_unpack_parent(&root.envelope()) { - inner(root, &mut Args { func, visitor })?; - } - - ControlFlow::Continue(()) -} - -/// Iterator type returned by `RTree::locate_*_mut` methods. -pub struct SelectionIteratorMut<'a, T, Func> -where - T: RTreeObject + 'a, - Func: SelectionFunction, -{ - func: Func, - current_nodes: SmallVec<[&'a mut RTreeNode; 32]>, -} - -impl<'a, T, Func> SelectionIteratorMut<'a, T, Func> -where - T: RTreeObject, - Func: SelectionFunction, -{ - pub(crate) fn new(root: &'a mut ParentNode, func: Func) -> Self { - let current_nodes = - if !root.children.is_empty() && func.should_unpack_parent(&root.envelope()) { - root.children.iter_mut().collect() - } else { - SmallVec::new() - }; - - SelectionIteratorMut { - func, - current_nodes, - } - } -} - -impl<'a, T, Func> Iterator for SelectionIteratorMut<'a, T, Func> -where - T: RTreeObject, - Func: SelectionFunction, -{ - type Item = &'a mut T; - - fn next(&mut self) -> Option<&'a mut T> { - while let Some(next) = self.current_nodes.pop() { - match next { - RTreeNode::Leaf(ref mut t) => { - if self.func.should_unpack_leaf(t) { - return Some(t); - } - } - RTreeNode::Parent(ref mut data) => { - if self.func.should_unpack_parent(&data.envelope) { - self.current_nodes.extend(&mut data.children); - } - } - } - } - None - } -} - -/// Internal iteration variant of [`SelectionIteratorMut`] -pub fn select_nodes_mut<'a, T, Func, V, B>( - root: &'a mut ParentNode, - func: &Func, - visitor: &mut V, -) -> ControlFlow -where - T: RTreeObject, - Func: SelectionFunction, - V: FnMut(&'a mut T) -> ControlFlow, -{ - struct Args<'a, Func, V> { - func: &'a Func, - visitor: &'a mut V, - } - - fn inner<'a, T, Func, V, B>( - parent: &'a mut ParentNode, - args: &mut Args<'_, Func, V>, - ) -> ControlFlow - where - T: RTreeObject, - Func: SelectionFunction, - V: FnMut(&'a mut T) -> ControlFlow, - { - for node in parent.children.iter_mut() { - match node { - RTreeNode::Leaf(ref mut t) => { - if args.func.should_unpack_leaf(t) { - (args.visitor)(t)?; - } - } - RTreeNode::Parent(ref mut data) => { - if args.func.should_unpack_parent(&data.envelope()) { - inner(data, args)?; - } - } - } - } - - ControlFlow::Continue(()) - } - - if !root.children.is_empty() && func.should_unpack_parent(&root.envelope()) { - inner(root, &mut Args { func, visitor })?; - } - - ControlFlow::Continue(()) -} - -#[cfg(test)] -mod test { - use crate::aabb::AABB; - use crate::envelope::Envelope; - use crate::object::RTreeObject; - use crate::rtree::RTree; - use crate::test_utilities::{create_random_points, create_random_rectangles, SEED_1}; - use crate::SelectionFunction; - - #[test] - fn test_root_node_is_not_always_unpacked() { - struct SelectNoneFunc {} - - impl SelectionFunction<[i32; 2]> for SelectNoneFunc { - fn should_unpack_parent(&self, _: &AABB<[i32; 2]>) -> bool { - false - } - } - - let mut tree = RTree::bulk_load(vec![[0i32, 0]]); - - let mut elements = tree.locate_with_selection_function(SelectNoneFunc {}); - assert!(elements.next().is_none()); - drop(elements); - - let mut elements = tree.locate_with_selection_function_mut(SelectNoneFunc {}); - assert!(elements.next().is_none()); - } - - #[test] - fn test_locate_all() { - const NUM_RECTANGLES: usize = 400; - let rectangles = create_random_rectangles(NUM_RECTANGLES, SEED_1); - let tree = RTree::bulk_load(rectangles.clone()); - - let query_points = create_random_points(20, SEED_1); - - for p in &query_points { - let contained_sequential: Vec<_> = rectangles - .iter() - .filter(|rectangle| rectangle.envelope().contains_point(p)) - .cloned() - .collect(); - - let contained_rtree: Vec<_> = tree.locate_all_at_point(p).cloned().collect(); - - contained_sequential - .iter() - .all(|r| contained_rtree.contains(r)); - contained_rtree - .iter() - .all(|r| contained_sequential.contains(r)); - } - } - - #[test] - fn test_locate_in_envelope() { - let points = create_random_points(100, SEED_1); - let tree = RTree::bulk_load(points.clone()); - let envelope = AABB::from_corners([0.5, 0.5], [1.0, 1.0]); - let contained_in_envelope: Vec<_> = points - .iter() - .filter(|point| envelope.contains_point(point)) - .cloned() - .collect(); - let len = contained_in_envelope.len(); - assert!(10 < len && len < 90, "unexpected point distribution"); - let located: Vec<_> = tree.locate_in_envelope(&envelope).cloned().collect(); - assert_eq!(len, located.len()); - for point in &contained_in_envelope { - assert!(located.contains(point)); - } - } - - #[test] - fn test_locate_with_selection_func() { - use crate::SelectionFunction; - - struct SelectLeftOfZeroPointFiveFunc; - - impl SelectionFunction<[f64; 2]> for SelectLeftOfZeroPointFiveFunc { - fn should_unpack_parent(&self, parent_envelope: &AABB<[f64; 2]>) -> bool { - parent_envelope.lower()[0] < 0.5 || parent_envelope.upper()[0] < 0.5 - } - - fn should_unpack_leaf(&self, child: &[f64; 2]) -> bool { - child[0] < 0.5 - } - } - - let func = SelectLeftOfZeroPointFiveFunc; - - let points = create_random_points(100, SEED_1); - let tree = RTree::bulk_load(points.clone()); - let iterative_count = points - .iter() - .filter(|leaf| func.should_unpack_leaf(leaf)) - .count(); - let selected = tree - .locate_with_selection_function(func) - .collect::>(); - - assert_eq!(iterative_count, selected.len()); - assert!(iterative_count > 20); // Make sure that we do test something interesting - for point in &selected { - assert!(point[0] < 0.5); - } - } - - #[test] - fn test_iteration() { - const NUM_POINTS: usize = 1000; - let points = create_random_points(NUM_POINTS, SEED_1); - let mut tree = RTree::new(); - for p in &points { - tree.insert(*p); - } - let mut count = 0usize; - for p in tree.iter() { - assert!(points.iter().any(|q| q == p)); - count += 1; - } - assert_eq!(count, NUM_POINTS); - count = 0; - for p in tree.iter_mut() { - assert!(points.iter().any(|q| q == p)); - count += 1; - } - assert_eq!(count, NUM_POINTS); - for p in &points { - assert!(tree.iter().any(|q| q == p)); - assert!(tree.iter_mut().any(|q| q == p)); - } - } - - #[test] - fn test_locate_within_distance() { - use crate::primitives::Line; - - let points = create_random_points(100, SEED_1); - let tree = RTree::bulk_load(points.clone()); - let circle_radius_2 = 0.3; - let circle_origin = [0.2, 0.6]; - let contained_in_circle: Vec<_> = points - .iter() - .filter(|point| Line::new(circle_origin, **point).length_2() <= circle_radius_2) - .cloned() - .collect(); - let located: Vec<_> = tree - .locate_within_distance(circle_origin, circle_radius_2) - .cloned() - .collect(); - - assert_eq!(located.len(), contained_in_circle.len()); - for point in &contained_in_circle { - assert!(located.contains(point)); - } - } - - #[test] - fn test_locate_within_distance_on_empty_tree() { - let tree: RTree<[f64; 3]> = RTree::new(); - tree.locate_within_distance([0.0, 0.0, 0.0], 10.0); - - let tree: RTree<[i64; 3]> = RTree::new(); - tree.locate_within_distance([0, 0, 0], 10); - } -} diff --git a/thirdparty/rstar/src/algorithm/mod.rs b/thirdparty/rstar/src/algorithm/mod.rs deleted file mode 100644 index cdaed99..0000000 --- a/thirdparty/rstar/src/algorithm/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub mod bulk_load; -pub mod intersection_iterator; -/// Iterator types -pub mod iterators; -pub mod nearest_neighbor; -pub mod removal; -pub mod rstar; -pub mod selection_functions; diff --git a/thirdparty/rstar/src/algorithm/nearest_neighbor.rs b/thirdparty/rstar/src/algorithm/nearest_neighbor.rs deleted file mode 100644 index 698b26d..0000000 --- a/thirdparty/rstar/src/algorithm/nearest_neighbor.rs +++ /dev/null @@ -1,405 +0,0 @@ -use crate::node::{ParentNode, RTreeNode}; -use crate::point::{min_inline, Point}; -use crate::{Envelope, PointDistance, RTreeObject}; - -use alloc::collections::BinaryHeap; -#[cfg(not(test))] -use alloc::{vec, vec::Vec}; -use core::mem::replace; -use heapless::binary_heap as static_heap; -use num_traits::Bounded; - -struct RTreeNodeDistanceWrapper<'a, T> -where - T: PointDistance + 'a, -{ - node: &'a RTreeNode, - distance: <::Point as Point>::Scalar, -} - -impl<'a, T> PartialEq for RTreeNodeDistanceWrapper<'a, T> -where - T: PointDistance, -{ - fn eq(&self, other: &Self) -> bool { - self.distance == other.distance - } -} - -impl<'a, T> PartialOrd for RTreeNodeDistanceWrapper<'a, T> -where - T: PointDistance, -{ - fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> { - Some(self.cmp(other)) - } -} - -impl<'a, T> Eq for RTreeNodeDistanceWrapper<'a, T> where T: PointDistance {} - -impl<'a, T> Ord for RTreeNodeDistanceWrapper<'a, T> -where - T: PointDistance, -{ - fn cmp(&self, other: &Self) -> ::core::cmp::Ordering { - // Inverse comparison creates a min heap - other.distance.partial_cmp(&self.distance).unwrap() - } -} - -impl<'a, T> NearestNeighborDistance2Iterator<'a, T> -where - T: PointDistance, -{ - pub fn new(root: &'a ParentNode, query_point: ::Point) -> Self { - let mut result = NearestNeighborDistance2Iterator { - nodes: SmallHeap::new(), - query_point, - }; - result.extend_heap(&root.children); - result - } - - fn extend_heap(&mut self, children: &'a [RTreeNode]) { - let &mut NearestNeighborDistance2Iterator { - ref mut nodes, - ref query_point, - } = self; - nodes.extend(children.iter().map(|child| { - let distance = match child { - RTreeNode::Parent(ref data) => data.envelope.distance_2(query_point), - RTreeNode::Leaf(ref t) => t.distance_2(query_point), - }; - - RTreeNodeDistanceWrapper { - node: child, - distance, - } - })); - } -} - -impl<'a, T> Iterator for NearestNeighborDistance2Iterator<'a, T> -where - T: PointDistance, -{ - type Item = (&'a T, <::Point as Point>::Scalar); - - fn next(&mut self) -> Option { - while let Some(current) = self.nodes.pop() { - match current { - RTreeNodeDistanceWrapper { - node: RTreeNode::Parent(ref data), - .. - } => { - self.extend_heap(&data.children); - } - RTreeNodeDistanceWrapper { - node: RTreeNode::Leaf(ref t), - distance, - } => { - return Some((t, distance)); - } - } - } - None - } -} - -pub struct NearestNeighborDistance2Iterator<'a, T> -where - T: PointDistance + 'a, -{ - nodes: SmallHeap>, - query_point: ::Point, -} - -impl<'a, T> NearestNeighborIterator<'a, T> -where - T: PointDistance, -{ - pub fn new(root: &'a ParentNode, query_point: ::Point) -> Self { - NearestNeighborIterator { - iter: NearestNeighborDistance2Iterator::new(root, query_point), - } - } -} - -impl<'a, T> Iterator for NearestNeighborIterator<'a, T> -where - T: PointDistance, -{ - type Item = &'a T; - - fn next(&mut self) -> Option { - self.iter.next().map(|(t, _distance)| t) - } -} - -pub struct NearestNeighborIterator<'a, T> -where - T: PointDistance + 'a, -{ - iter: NearestNeighborDistance2Iterator<'a, T>, -} - -enum SmallHeap { - Stack(static_heap::BinaryHeap), - Heap(BinaryHeap), -} - -impl SmallHeap { - pub fn new() -> Self { - Self::Stack(static_heap::BinaryHeap::new()) - } - - pub fn pop(&mut self) -> Option { - match self { - SmallHeap::Stack(heap) => heap.pop(), - SmallHeap::Heap(heap) => heap.pop(), - } - } - - pub fn push(&mut self, item: T) { - match self { - SmallHeap::Stack(heap) => { - if let Err(item) = heap.push(item) { - let capacity = heap.len() + 1; - let new_heap = self.spill(capacity); - new_heap.push(item); - } - } - SmallHeap::Heap(heap) => heap.push(item), - } - } - - pub fn extend(&mut self, iter: I) - where - I: ExactSizeIterator, - { - match self { - SmallHeap::Stack(heap) => { - if heap.capacity() >= heap.len() + iter.len() { - for item in iter { - if heap.push(item).is_err() { - unreachable!(); - } - } - } else { - let capacity = heap.len() + iter.len(); - let new_heap = self.spill(capacity); - new_heap.extend(iter); - } - } - SmallHeap::Heap(heap) => heap.extend(iter), - } - } - - #[cold] - fn spill(&mut self, capacity: usize) -> &mut BinaryHeap { - let new_heap = BinaryHeap::with_capacity(capacity); - let old_heap = replace(self, SmallHeap::Heap(new_heap)); - - let new_heap = match self { - SmallHeap::Heap(new_heap) => new_heap, - SmallHeap::Stack(_) => unreachable!(), - }; - let old_heap = match old_heap { - SmallHeap::Stack(old_heap) => old_heap, - SmallHeap::Heap(_) => unreachable!(), - }; - - new_heap.extend(old_heap.into_vec()); - - new_heap - } -} - -pub fn nearest_neighbor( - node: &ParentNode, - query_point: ::Point, -) -> Option<&T> -where - T: PointDistance, -{ - fn extend_heap<'a, T>( - nodes: &mut SmallHeap>, - node: &'a ParentNode, - query_point: ::Point, - min_max_distance: &mut <::Point as Point>::Scalar, - ) where - T: PointDistance + 'a, - { - for child in &node.children { - let distance_if_less_or_equal = match child { - RTreeNode::Parent(ref data) => { - let distance = data.envelope.distance_2(&query_point); - if distance <= *min_max_distance { - Some(distance) - } else { - None - } - } - RTreeNode::Leaf(ref t) => { - t.distance_2_if_less_or_equal(&query_point, *min_max_distance) - } - }; - if let Some(distance) = distance_if_less_or_equal { - *min_max_distance = min_inline( - *min_max_distance, - child.envelope().min_max_dist_2(&query_point), - ); - nodes.push(RTreeNodeDistanceWrapper { - node: child, - distance, - }); - } - } - } - - // Calculate smallest minmax-distance - let mut smallest_min_max: <::Point as Point>::Scalar = - Bounded::max_value(); - let mut nodes = SmallHeap::new(); - extend_heap(&mut nodes, node, query_point.clone(), &mut smallest_min_max); - while let Some(current) = nodes.pop() { - match current { - RTreeNodeDistanceWrapper { - node: RTreeNode::Parent(ref data), - .. - } => { - extend_heap(&mut nodes, data, query_point.clone(), &mut smallest_min_max); - } - RTreeNodeDistanceWrapper { - node: RTreeNode::Leaf(ref t), - .. - } => { - return Some(t); - } - } - } - None -} - -pub fn nearest_neighbors( - node: &ParentNode, - query_point: ::Point, -) -> Vec<&T> -where - T: PointDistance, -{ - let mut nearest_neighbors = NearestNeighborDistance2Iterator::new(node, query_point.clone()); - - let (first, first_distance_2) = match nearest_neighbors.next() { - Some(item) => item, - // If we have an empty tree, just return an empty vector. - None => return Vec::new(), - }; - - // The result will at least contain the first nearest neighbor. - let mut result = vec![first]; - - // Use the distance to the first nearest neighbor - // to filter out the rest of the nearest neighbors - // that are farther than this first neighbor. - result.extend( - nearest_neighbors - .take_while(|(_, next_distance_2)| next_distance_2 == &first_distance_2) - .map(|(next, _)| next), - ); - - result -} - -#[cfg(test)] -mod test { - use crate::object::PointDistance; - use crate::rtree::RTree; - use crate::test_utilities::*; - - #[test] - fn test_nearest_neighbor_empty() { - let tree: RTree<[f32; 2]> = RTree::new(); - assert!(tree.nearest_neighbor(&[0.0, 213.0]).is_none()); - } - - #[test] - fn test_nearest_neighbor() { - let points = create_random_points(1000, SEED_1); - let tree = RTree::bulk_load(points.clone()); - - let sample_points = create_random_points(100, SEED_2); - for sample_point in &sample_points { - let mut nearest = None; - let mut closest_dist = f64::INFINITY; - for point in &points { - let delta = [point[0] - sample_point[0], point[1] - sample_point[1]]; - let new_dist = delta[0] * delta[0] + delta[1] * delta[1]; - if new_dist < closest_dist { - closest_dist = new_dist; - nearest = Some(point); - } - } - assert_eq!(nearest, tree.nearest_neighbor(sample_point)); - } - } - - #[test] - fn test_nearest_neighbors_empty() { - let tree: RTree<[f32; 2]> = RTree::new(); - assert!(tree.nearest_neighbors(&[0.0, 213.0]).is_empty()); - } - - #[test] - fn test_nearest_neighbors() { - let points = create_random_points(1000, SEED_1); - let tree = RTree::bulk_load(points); - - let sample_points = create_random_points(50, SEED_2); - for sample_point in &sample_points { - let nearest_neighbors = tree.nearest_neighbors(sample_point); - let mut distance = -1.0; - for nn in &nearest_neighbors { - if distance < 0.0 { - distance = sample_point.distance_2(nn); - } else { - let new_distance = sample_point.distance_2(nn); - assert_eq!(new_distance, distance); - } - } - } - } - - #[test] - fn test_nearest_neighbor_iterator() { - let mut points = create_random_points(1000, SEED_1); - let tree = RTree::bulk_load(points.clone()); - - let sample_points = create_random_points(50, SEED_2); - for sample_point in &sample_points { - points.sort_by(|r, l| { - r.distance_2(sample_point) - .partial_cmp(&l.distance_2(sample_point)) - .unwrap() - }); - let collected: Vec<_> = tree.nearest_neighbor_iter(sample_point).cloned().collect(); - assert_eq!(points, collected); - } - } - - #[test] - fn test_nearest_neighbor_iterator_with_distance_2() { - let points = create_random_points(1000, SEED_2); - let tree = RTree::bulk_load(points); - - let sample_points = create_random_points(50, SEED_1); - for sample_point in &sample_points { - let mut last_distance = 0.0; - for (point, distance) in tree.nearest_neighbor_iter_with_distance_2(sample_point) { - assert_eq!(point.distance_2(sample_point), distance); - assert!(last_distance < distance); - last_distance = distance; - } - } - } -} diff --git a/thirdparty/rstar/src/algorithm/removal.rs b/thirdparty/rstar/src/algorithm/removal.rs deleted file mode 100644 index 0bf5baa..0000000 --- a/thirdparty/rstar/src/algorithm/removal.rs +++ /dev/null @@ -1,397 +0,0 @@ -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}; - -#[cfg(not(test))] -use alloc::{vec, vec::Vec}; - -#[allow(unused_imports)] // Import is required when building without std -use num_traits::Float; - -/// Iterator returned by `impl IntoIter for RTree`. -/// -/// Consumes the whole tree and yields all leaf objects. -pub struct IntoIter -where - T: RTreeObject, -{ - node_stack: Vec>, -} - -impl IntoIter -where - T: RTreeObject, -{ - pub(crate) fn new(root: ParentNode) -> Self { - Self { - node_stack: vec![RTreeNode::Parent(root)], - } - } -} - -impl Iterator for IntoIter -where - T: RTreeObject, -{ - type Item = T; - - fn next(&mut self) -> Option { - while let Some(node) = self.node_stack.pop() { - match node { - RTreeNode::Leaf(object) => return Some(object), - RTreeNode::Parent(parent) => self.node_stack.extend(parent.children), - } - } - - None - } -} - -/// Iterator returned by `RTree::drain_*` methods. -/// -/// Draining iterator that removes elements of the tree selected by a -/// [`SelectionFunction`]. Returned by -/// [`RTree::drain_with_selection_function`] and related methods. -/// -/// # Remarks -/// -/// This iterator is similar to the one returned by `Vec::drain` or -/// `Vec::drain_filter`. Dropping the iterator at any point removes only -/// 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> -where - T: RTreeObject, - Params: RTreeParams, - R: SelectionFunction, -{ - node_stack: Vec<(ParentNode, usize, usize)>, - removal_function: R, - rtree: &'a mut RTree, - original_size: usize, -} - -impl<'a, T, R, Params> DrainIterator<'a, T, R, Params> -where - T: RTreeObject, - Params: RTreeParams, - R: SelectionFunction, -{ - 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. - - // Instead of using `new_with_params`, we avoid an allocation for - // the normal usage and replace root with an empty `Vec`. - let root = replace( - rtree.root_mut(), - ParentNode { - children: vec![], - envelope: Envelope::new_empty(), - }, - ); - let original_size = replace(rtree.size_mut(), 0); - - let m = 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)); - - DrainIterator { - node_stack, - original_size, - removal_function, - rtree, - } - } - - fn pop_node(&mut self, increment_idx: bool) -> Option<(ParentNode, usize)> { - debug_assert!(!self.node_stack.is_empty()); - - let (mut node, _, num_removed) = self.node_stack.pop().unwrap(); - - // We only compute envelope for the current node as the parent - // is taken care of when it is popped. - - // TODO: May be make this a method on `ParentNode` - if num_removed > 0 { - node.envelope = crate::node::envelope_for_children(&node.children); - } - - // If there is no parent, this is the new root node to set back in the rtree - // O/w, get the new top in stack - let (parent_node, parent_idx, parent_removed) = match self.node_stack.last_mut() { - Some(pn) => (&mut pn.0, &mut pn.1, &mut pn.2), - None => return Some((node, num_removed)), - }; - - // Update the remove count on parent - *parent_removed += num_removed; - - // If the node has no children, we don't need to add it back to the parent - if node.children.is_empty() { - return None; - } - - // Put the child back (but re-arranged) - parent_node.children.push(RTreeNode::Parent(node)); - - // Swap it with the current item and increment idx. - - // A minor optimization is to avoid the swap in the destructor, - // where we aren't going to be iterating any more. - if !increment_idx { - return None; - } - - // Note that during iteration, parent_idx may be equal to - // (previous) children.len(), but this is okay as the swap will be - // a no-op. - let parent_len = parent_node.children.len(); - parent_node.children.swap(*parent_idx, parent_len - 1); - *parent_idx += 1; - - None - } -} - -impl<'a, T, R, Params> Iterator for DrainIterator<'a, T, R, Params> -where - T: RTreeObject, - Params: RTreeParams, - R: SelectionFunction, -{ - type Item = T; - - fn next(&mut self) -> Option { - 'attempt_loop: loop { - // Get reference to top node or return None. - let (node, idx, remove_count) = match self.node_stack.last_mut() { - Some(node) => (&mut node.0, &mut node.1, &mut node.2), - None => return None, - }; - - // Try to find a selected item to return. - if *idx > 0 || self.removal_function.should_unpack_parent(&node.envelope) { - while *idx < node.children.len() { - match &mut node.children[*idx] { - RTreeNode::Parent(_) => { - // Swap node with last, remove and return the value. - // No need to increment idx as something else has replaced it; - // or idx == new len, and we'll handle it in the next iteration. - let child = match node.children.swap_remove(*idx) { - RTreeNode::Leaf(_) => unreachable!("DrainIterator bug!"), - RTreeNode::Parent(node) => node, - }; - self.node_stack.push((child, 0, 0)); - continue 'attempt_loop; - } - RTreeNode::Leaf(ref leaf) => { - if self.removal_function.should_unpack_leaf(leaf) { - // Swap node with last, remove and return the value. - // No need to increment idx as something else has replaced it; - // or idx == new len, and we'll handle it in the next iteration. - *remove_count += 1; - return match node.children.swap_remove(*idx) { - RTreeNode::Leaf(data) => Some(data), - _ => unreachable!("RemovalIterator bug!"), - }; - } - *idx += 1; - } - } - } - } - - // Pop top node and clean-up if done - if let Some((new_root, total_removed)) = self.pop_node(true) { - // This happens if we are done with the iteration. - // Set the root back in rtree and return None - *self.rtree.root_mut() = new_root; - *self.rtree.size_mut() = self.original_size - total_removed; - return None; - } - } - } -} - -impl<'a, T, R, Params> Drop for DrainIterator<'a, T, R, Params> -where - T: RTreeObject, - Params: RTreeParams, - R: SelectionFunction, -{ - fn drop(&mut self) { - // Re-assemble back the original rtree and update envelope as we - // re-assemble. - if self.node_stack.is_empty() { - // The iteration handled everything, nothing to do. - return; - } - - loop { - debug_assert!(!self.node_stack.is_empty()); - if let Some((new_root, total_removed)) = self.pop_node(false) { - *self.rtree.root_mut() = new_root; - *self.rtree.size_mut() = self.original_size - total_removed; - break; - } - } - } -} - -#[cfg(test)] -mod test { - use std::mem::forget; - - use crate::algorithm::selection_functions::{SelectAllFunc, SelectInEnvelopeFuncIntersecting}; - use crate::point::PointExt; - use crate::primitives::Line; - use crate::test_utilities::{create_random_points, create_random_rectangles, SEED_1, SEED_2}; - use crate::AABB; - - use super::*; - - #[test] - fn test_remove_and_insert() { - const SIZE: usize = 1000; - let points = create_random_points(SIZE, SEED_1); - let later_insertions = create_random_points(SIZE, SEED_2); - let mut tree = RTree::bulk_load(points.clone()); - for (point_to_remove, point_to_add) in points.iter().zip(later_insertions.iter()) { - assert!(tree.remove_at_point(point_to_remove).is_some()); - tree.insert(*point_to_add); - } - assert_eq!(tree.size(), SIZE); - assert!(points.iter().all(|p| !tree.contains(p))); - assert!(later_insertions.iter().all(|p| tree.contains(p))); - for point in &later_insertions { - assert!(tree.remove_at_point(point).is_some()); - } - assert_eq!(tree.size(), 0); - } - - #[test] - fn test_remove_and_insert_rectangles() { - const SIZE: usize = 1000; - let initial_rectangles = create_random_rectangles(SIZE, SEED_1); - let new_rectangles = create_random_rectangles(SIZE, SEED_2); - let mut tree = RTree::bulk_load(initial_rectangles.clone()); - - for (rectangle_to_remove, rectangle_to_add) in - initial_rectangles.iter().zip(new_rectangles.iter()) - { - assert!(tree.remove(rectangle_to_remove).is_some()); - tree.insert(*rectangle_to_add); - } - assert_eq!(tree.size(), SIZE); - assert!(initial_rectangles.iter().all(|p| !tree.contains(p))); - assert!(new_rectangles.iter().all(|p| tree.contains(p))); - for rectangle in &new_rectangles { - assert!(tree.contains(rectangle)); - } - for rectangle in &initial_rectangles { - assert!(!tree.contains(rectangle)); - } - for rectangle in &new_rectangles { - assert!(tree.remove(rectangle).is_some()); - } - assert_eq!(tree.size(), 0); - } - - #[test] - fn test_remove_at_point() { - let points = create_random_points(1000, SEED_1); - let mut tree = RTree::bulk_load(points.clone()); - for point in &points { - let size_before_removal = tree.size(); - assert!(tree.remove_at_point(point).is_some()); - assert!(tree.remove_at_point(&[1000.0, 1000.0]).is_none()); - assert_eq!(size_before_removal - 1, tree.size()); - } - } - - #[test] - fn test_remove() { - let points = create_random_points(1000, SEED_1); - let offsets = create_random_points(1000, SEED_2); - let scaled = offsets.iter().map(|p| p.mul(0.05)); - let edges: Vec<_> = points - .iter() - .zip(scaled) - .map(|(from, offset)| Line::new(*from, from.add(&offset))) - .collect(); - let mut tree = RTree::bulk_load(edges.clone()); - for edge in &edges { - let size_before_removal = tree.size(); - assert!(tree.remove(edge).is_some()); - assert!(tree.remove(edge).is_none()); - assert_eq!(size_before_removal - 1, tree.size()); - } - } - - #[test] - fn test_drain_iterator() { - const SIZE: usize = 1000; - let points = create_random_points(SIZE, SEED_1); - let mut tree = RTree::bulk_load(points); - - let drain_count = DrainIterator::new(&mut tree, SelectAllFunc) - .take(250) - .count(); - assert_eq!(drain_count, 250); - assert_eq!(tree.size(), 750); - - let drain_count = DrainIterator::new(&mut tree, SelectAllFunc) - .take(250) - .count(); - assert_eq!(drain_count, 250); - assert_eq!(tree.size(), 500); - - // Test Drain forget soundness - forget(DrainIterator::new(&mut tree, SelectAllFunc)); - // Check tree has no nodes - // Tests below will check the same tree can be used again - assert_eq!(tree.size(), 0); - - let points = create_random_points(1000, SEED_1); - points.into_iter().for_each(|pt| tree.insert(pt)); - - // The total for this is 406 (for SEED_1) - let env = AABB::from_corners([-2., -0.6], [0.5, 0.85]); - - let sel = SelectInEnvelopeFuncIntersecting::new(env); - let drain_count = DrainIterator::new(&mut tree, sel).take(80).count(); - assert_eq!(drain_count, 80); - - let sel = SelectInEnvelopeFuncIntersecting::new(env); - let drain_count = DrainIterator::new(&mut tree, sel).count(); - assert_eq!(drain_count, 326); - - let sel = SelectInEnvelopeFuncIntersecting::new(env); - let sel_count = tree.locate_with_selection_function(sel).count(); - assert_eq!(sel_count, 0); - assert_eq!(tree.size(), 1000 - 80 - 326); - } - - #[test] - fn test_into_iter() { - const SIZE: usize = 100; - let mut points = create_random_points(SIZE, SEED_1); - let tree = RTree::bulk_load(points.clone()); - - let mut vec = tree.into_iter().collect::>(); - - assert_eq!(vec.len(), points.len()); - - points.sort_unstable_by(|lhs, rhs| lhs.partial_cmp(rhs).unwrap()); - vec.sort_unstable_by(|lhs, rhs| lhs.partial_cmp(rhs).unwrap()); - - assert_eq!(points, vec); - } -} diff --git a/thirdparty/rstar/src/algorithm/rstar.rs b/thirdparty/rstar/src/algorithm/rstar.rs deleted file mode 100644 index 9127037..0000000 --- a/thirdparty/rstar/src/algorithm/rstar.rs +++ /dev/null @@ -1,354 +0,0 @@ -use crate::envelope::Envelope; -use crate::node::{envelope_for_children, ParentNode, RTreeNode}; -use crate::object::RTreeObject; -use crate::params::{InsertionStrategy, RTreeParams}; -use crate::point::{Point, PointExt}; -use crate::rtree::RTree; - -#[cfg(not(test))] -use alloc::vec::Vec; -use num_traits::{Bounded, Zero}; - -/// Inserts points according to the r-star heuristic. -/// -/// The r*-heuristic focusses on good insertion quality at the costs of -/// insertion performance. This strategy is best for use cases with few -/// insertions and many nearest neighbor queries. -/// -/// `RStarInsertionStrategy` is used as the default insertion strategy. -/// See [InsertionStrategy] for more information on insertion strategies. -pub enum RStarInsertionStrategy {} - -enum InsertionResult -where - T: RTreeObject, -{ - Split(RTreeNode), - Reinsert(Vec>, usize), - Complete, -} - -impl InsertionStrategy for RStarInsertionStrategy { - fn insert(tree: &mut RTree, t: T) - where - Params: RTreeParams, - T: RTreeObject, - { - use InsertionAction::*; - - enum InsertionAction { - PerformSplit(RTreeNode), - PerformReinsert(RTreeNode), - } - - 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; - } - 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 => {} - } - } - } - } - } -} - -fn forced_insertion( - 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); - - 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); - } - - if let RTreeNode::Parent(ref mut follow) = node.children[expand_index] { - 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) - } - other => other, - } - } else { - unreachable!("This is a bug in rstar.") - } -} - -fn recursive_insert( - 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); - - if node.children.len() < expand_index { - // Force insertion into this node - node.children.push(t); - 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) - } else { - panic!("This is a bug in rstar.") - }; - - match expand { - InsertionResult::Split(child) => { - node.envelope.merge(&child.envelope()); - node.children.push(child); - resolve_overflow::<_, Params>(node, current_height) - } - InsertionResult::Reinsert(a, b) => { - node.envelope = envelope_for_children(&node.children); - InsertionResult::Reinsert(a, b) - } - other => other, - } -} - -fn choose_subtree(node: &ParentNode, to_insert: &RTreeNode) -> usize -where - T: RTreeObject, -{ - let all_leaves = match node.children.first() { - Some(RTreeNode::Leaf(_)) => return usize::MAX, - Some(RTreeNode::Parent(ref data)) => data - .children - .first() - .map(RTreeNode::is_leaf) - .unwrap_or(true), - None => return usize::MAX, - }; - - let zero: <::Point as Point>::Scalar = Zero::zero(); - let insertion_envelope = to_insert.envelope(); - let mut inclusion_count = 0; - let mut min_area = <::Point as Point>::Scalar::max_value(); - let mut min_index = 0; - for (index, child) in node.children.iter().enumerate() { - let envelope = child.envelope(); - if envelope.contains_envelope(&insertion_envelope) { - inclusion_count += 1; - let area = envelope.area(); - if area < min_area { - min_area = area; - min_index = index; - } - } - } - if inclusion_count == 0 { - // No inclusion found, subtree depends on overlap and area increase - let mut min = (zero, zero, zero); - - for (index, child1) in node.children.iter().enumerate() { - let envelope = child1.envelope(); - let mut new_envelope = envelope.clone(); - new_envelope.merge(&insertion_envelope); - let overlap_increase = if all_leaves { - // Calculate minimal overlap increase - let mut overlap = zero; - let mut new_overlap = zero; - for child2 in &node.children { - if child1 as *const _ != child2 as *const _ { - let child_envelope = child2.envelope(); - let temp1 = envelope.intersection_area(&child_envelope); - overlap = overlap + temp1; - let temp2 = new_envelope.intersection_area(&child_envelope); - new_overlap = new_overlap + temp2; - } - } - new_overlap - overlap - } else { - // Don't calculate overlap increase if not all children are leaves - zero - }; - // Calculate area increase and area - let area = new_envelope.area(); - let area_increase = area - envelope.area(); - let new_min = (overlap_increase, area_increase, area); - if new_min < min || index == 0 { - min = new_min; - min_index = index; - } - } - } - min_index -} - -// Never returns a request for reinsertion -fn resolve_overflow_without_reinsertion(node: &mut ParentNode) -> InsertionResult -where - T: RTreeObject, - Params: RTreeParams, -{ - 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 -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); - InsertionResult::Reinsert(nodes_for_reinsertion, current_depth) - } else { - InsertionResult::Complete - } -} - -fn split(node: &mut ParentNode) -> RTreeNode -where - T: RTreeObject, - Params: RTreeParams, -{ - 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 mut best_index = min_size; - - for k in min_size..=node.children.len() - min_size { - let mut first_envelope = node.children[k - 1].envelope(); - let mut second_envelope = node.children[k].envelope(); - let (l, r) = node.children.split_at(k); - for child in l { - first_envelope.merge(&child.envelope()); - } - for child in r { - second_envelope.merge(&child.envelope()); - } - - let overlap_value = first_envelope.intersection_area(&second_envelope); - let area_value = first_envelope.area() + second_envelope.area(); - let new_best = (overlap_value, area_value); - if new_best < best || k == min_size { - best = new_best; - best_index = k; - } - } - let off_split = node.children.split_off(best_index); - node.envelope = envelope_for_children(&node.children); - RTreeNode::Parent(ParentNode::new_parent(off_split)) -} - -fn get_split_axis(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 until = node.children.len() - min_size + 1; - for axis in 0..::Point::DIMENSIONS { - // Sort children along the current axis - T::Envelope::sort_envelopes(axis, &mut node.children); - let mut first_envelope = T::Envelope::new_empty(); - let mut second_envelope = T::Envelope::new_empty(); - for child in &node.children[..min_size] { - first_envelope.merge(&child.envelope()); - } - for child in &node.children[until..] { - second_envelope.merge(&child.envelope()); - } - for k in min_size..until { - let mut first_modified = first_envelope.clone(); - let mut second_modified = second_envelope.clone(); - let (l, r) = node.children.split_at(k); - for child in l { - first_modified.merge(&child.envelope()); - } - for child in r { - second_modified.merge(&child.envelope()); - } - - let perimeter_value = - first_modified.perimeter_value() + second_modified.perimeter_value(); - if best_goodness > perimeter_value { - best_axis = axis; - best_goodness = perimeter_value; - } - } - } - best_axis -} - -fn get_nodes_for_reinsertion(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 - node.children.sort_unstable_by(|l, r| { - let l_center = l.envelope().center(); - let r_center = r.envelope().center(); - l_center - .sub(¢er) - .length_2() - .partial_cmp(&(r_center.sub(¢er)).length_2()) - .unwrap() - }); - let num_children = node.children.len(); - let result = node - .children - .split_off(num_children - Params::REINSERTION_COUNT); - node.envelope = envelope_for_children(&node.children); - result -} diff --git a/thirdparty/rstar/src/algorithm/selection_functions.rs b/thirdparty/rstar/src/algorithm/selection_functions.rs deleted file mode 100644 index 3df80ae..0000000 --- a/thirdparty/rstar/src/algorithm/selection_functions.rs +++ /dev/null @@ -1,241 +0,0 @@ -use crate::envelope::Envelope; -use crate::object::PointDistance; -use crate::object::RTreeObject; -use crate::Point; - -/// Advanced trait to iterate through an r-tree. Usually it should not be required to be implemented. -/// -/// It is important to know some details about the inner structure of -/// r-trees to understand this trait. Any node in an r-tree is either a *leaf* (containing exactly one `T: RTreeObject`) or -/// a *parent* (containing multiple nodes). -/// The main benefit of r-trees lies in their ability to efficiently guide searches through -/// the tree. This is done by *pruning*: Knowing the envelopes of parent nodes -/// often allows the search to completely skip them and all contained children instead of having -/// to iterate through them, e.g. when searching for elements in a non-intersecting envelope. -/// This often reduces the expected time from `O(n)` to `O(log(n))`. -/// -/// This trait can be used to define searches through the r-tree by defining whether a node -/// should be further investigated ("unpacked") or pruned. -/// -/// Usually, the various `locate_[...]` methods of [`super::super::RTree`] should cover most -/// common searches. Otherwise, implementing `SelectionFunction` and using -/// [`crate::RTree::locate_with_selection_function`] -/// can be used to tailor a custom search. -pub trait SelectionFunction -where - T: RTreeObject, -{ - /// Return `true` if a parent node should be unpacked during a search. - /// - /// The parent node's envelope is given to guide the decision. - fn should_unpack_parent(&self, envelope: &T::Envelope) -> bool; - - /// Returns `true` if a given child node should be returned during a search. - /// The default implementation will always return `true`. - fn should_unpack_leaf(&self, _leaf: &T) -> bool { - true - } -} - -pub struct SelectInEnvelopeFunction -where - T: RTreeObject, -{ - envelope: T::Envelope, -} - -impl SelectInEnvelopeFunction -where - T: RTreeObject, -{ - pub fn new(envelope: T::Envelope) -> Self { - SelectInEnvelopeFunction { envelope } - } -} - -impl SelectionFunction for SelectInEnvelopeFunction -where - T: RTreeObject, -{ - fn should_unpack_parent(&self, parent_envelope: &T::Envelope) -> bool { - self.envelope.intersects(parent_envelope) - } - - fn should_unpack_leaf(&self, leaf: &T) -> bool { - self.envelope.contains_envelope(&leaf.envelope()) - } -} - -pub struct SelectInEnvelopeFuncIntersecting -where - T: RTreeObject, -{ - envelope: T::Envelope, -} - -impl SelectInEnvelopeFuncIntersecting -where - T: RTreeObject, -{ - pub fn new(envelope: T::Envelope) -> Self { - SelectInEnvelopeFuncIntersecting { envelope } - } -} - -impl SelectionFunction for SelectInEnvelopeFuncIntersecting -where - T: RTreeObject, -{ - fn should_unpack_parent(&self, envelope: &T::Envelope) -> bool { - self.envelope.intersects(envelope) - } - - fn should_unpack_leaf(&self, leaf: &T) -> bool { - leaf.envelope().intersects(&self.envelope) - } -} - -pub struct SelectAllFunc; - -impl SelectionFunction for SelectAllFunc -where - T: RTreeObject, -{ - fn should_unpack_parent(&self, _: &T::Envelope) -> bool { - true - } -} - -/// A [trait.SelectionFunction] that only selects elements whose envelope -/// contains a specific point. -pub struct SelectAtPointFunction -where - T: RTreeObject, -{ - point: ::Point, -} - -impl SelectAtPointFunction -where - T: PointDistance, -{ - pub fn new(point: ::Point) -> Self { - SelectAtPointFunction { point } - } -} - -impl SelectionFunction for SelectAtPointFunction -where - T: PointDistance, -{ - fn should_unpack_parent(&self, envelope: &T::Envelope) -> bool { - envelope.contains_point(&self.point) - } - - fn should_unpack_leaf(&self, leaf: &T) -> bool { - leaf.contains_point(&self.point) - } -} - -/// A selection function that only chooses elements equal (`==`) to a -/// given element -pub struct SelectEqualsFunction<'a, T> -where - T: RTreeObject + PartialEq + 'a, -{ - /// Only elements equal to this object will be removed. - object_to_remove: &'a T, -} - -impl<'a, T> SelectEqualsFunction<'a, T> -where - T: RTreeObject + PartialEq, -{ - pub fn new(object_to_remove: &'a T) -> Self { - SelectEqualsFunction { object_to_remove } - } -} - -impl<'a, T> SelectionFunction for SelectEqualsFunction<'a, T> -where - T: RTreeObject + PartialEq, -{ - fn should_unpack_parent(&self, parent_envelope: &T::Envelope) -> bool { - parent_envelope.contains_envelope(&self.object_to_remove.envelope()) - } - - fn should_unpack_leaf(&self, leaf: &T) -> bool { - leaf == self.object_to_remove - } -} - -pub struct SelectWithinDistanceFunction -where - T: RTreeObject + PointDistance, -{ - circle_origin: ::Point, - squared_max_distance: <::Point as Point>::Scalar, -} - -impl SelectWithinDistanceFunction -where - T: RTreeObject + PointDistance, -{ - pub fn new( - circle_origin: ::Point, - squared_max_distance: <::Point as Point>::Scalar, - ) -> Self { - SelectWithinDistanceFunction { - circle_origin, - squared_max_distance, - } - } -} - -impl SelectionFunction for SelectWithinDistanceFunction -where - T: RTreeObject + PointDistance, -{ - fn should_unpack_parent(&self, parent_envelope: &T::Envelope) -> bool { - let envelope_distance = parent_envelope.distance_2(&self.circle_origin); - envelope_distance <= self.squared_max_distance - } - - fn should_unpack_leaf(&self, leaf: &T) -> bool { - leaf.distance_2_if_less_or_equal(&self.circle_origin, self.squared_max_distance) - .is_some() - } -} - -pub struct SelectByAddressFunction -where - T: RTreeObject, -{ - envelope: T::Envelope, - element_address: *const T, -} - -impl SelectByAddressFunction -where - T: RTreeObject, -{ - pub fn new(envelope: T::Envelope, element_address: &T) -> Self { - Self { - envelope, - element_address, - } - } -} - -impl SelectionFunction for SelectByAddressFunction -where - T: RTreeObject, -{ - fn should_unpack_parent(&self, parent_envelope: &T::Envelope) -> bool { - parent_envelope.contains_envelope(&self.envelope) - } - - fn should_unpack_leaf(&self, leaf: &T) -> bool { - core::ptr::eq(self.element_address, leaf) - } -} diff --git a/thirdparty/rstar/src/envelope.rs b/thirdparty/rstar/src/envelope.rs deleted file mode 100644 index 547194c..0000000 --- a/thirdparty/rstar/src/envelope.rs +++ /dev/null @@ -1,72 +0,0 @@ -use crate::{Point, RTreeObject}; - -/// An envelope type that encompasses some child nodes. -/// -/// An envelope defines how different bounding boxes of inserted children in an r-tree can interact, -/// e.g. how they can be merged or intersected. -/// This trait is not meant to be implemented by the user. Currently, only one implementation -/// exists ([crate::AABB]) and should be used. -pub trait Envelope: Clone + PartialEq + ::core::fmt::Debug { - /// The envelope's point type. - type Point: Point; - - /// Creates a new, empty envelope that does not encompass any child. - fn new_empty() -> Self; - - /// Returns true if a point is contained within this envelope. - fn contains_point(&self, point: &Self::Point) -> bool; - - /// Returns true if another envelope is _fully contained_ within `self`. - fn contains_envelope(&self, aabb: &Self) -> bool; - - /// Extends `self` to contain another envelope. - fn merge(&mut self, other: &Self); - /// Returns the minimal envelope containing `self` and another envelope. - fn merged(&self, other: &Self) -> Self; - - /// Returns true if `self` and `other` intersect. The intersection might be - /// of zero area (the two envelopes only touching each other). - fn intersects(&self, other: &Self) -> bool; - /// Returns the area of the intersection of `self` and another envelope. - fn intersection_area(&self, other: &Self) -> ::Scalar; - - /// Returns this envelope's area. Must be at least 0. - fn area(&self) -> ::Scalar; - - /// Returns the squared distance between the envelope's border and a point. - /// - /// # Notes - /// - While euclidean distance will be the correct choice for most use cases, any distance metric - /// fulfilling the [usual axioms](https://en.wikipedia.org/wiki/Metric_space) - /// can be used when implementing this method - /// - Implementers **must** ensure that the distance metric used matches that of [crate::PointDistance::distance_2] - fn distance_2(&self, point: &Self::Point) -> ::Scalar; - - /// Returns the squared min-max distance, a concept that helps to find nearest neighbors efficiently. - /// - /// Visually, if an AABB and a point are given, the min-max distance returns the distance at which we - /// can be assured that an element must be present. This serves as an upper bound during nearest neighbor search. - /// - /// # References - /// [Roussopoulos, Nick, Stephen Kelley, and Frédéric Vincent. "Nearest neighbor queries." ACM sigmod record. Vol. 24. No. 2. ACM, 1995.](https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.133.2288) - fn min_max_dist_2(&self, point: &Self::Point) -> ::Scalar; - - /// Returns the envelope's center point. - fn center(&self) -> Self::Point; - - /// Returns a value proportional to the envelope's perimeter. - fn perimeter_value(&self) -> ::Scalar; - - /// Sorts a given set of objects with envelopes along one of their axes. - fn sort_envelopes>(axis: usize, envelopes: &mut [T]); - - /// Partitions objects with an envelope along a certain axis. - /// - /// After calling this, envelopes[0..selection_size] are all smaller - /// than envelopes[selection_size + 1..]. - fn partition_envelopes>( - axis: usize, - envelopes: &mut [T], - selection_size: usize, - ); -} diff --git a/thirdparty/rstar/src/lib.rs b/thirdparty/rstar/src/lib.rs deleted file mode 100644 index 5fd7131..0000000 --- a/thirdparty/rstar/src/lib.rs +++ /dev/null @@ -1,64 +0,0 @@ -//! An n-dimensional [r*-tree](https://en.wikipedia.org/wiki/R*-tree) implementation for use as a spatial index. -//! -//! This crate implements a flexible, n-dimensional r-tree implementation with -//! the r* (r star) insertion strategy. -//! -//! # R-Tree -//! An r-tree is a data structure containing _spatial data_, optimized for -//! nearest neighbor search. -//! _Spatial data_ refers to an object that has the notion of a position and extent: -//! for example points, lines and rectangles in any dimension. -//! -//! -//! # Further documentation -//! The crate's main data structure and documentation is the [RTree] struct. -//! -//! ## Primitives -//! The pre-defined primitives like lines and rectangles contained in -//! the [primitives module](crate::primitives) may be of interest for a quick start. -//! ## `Geo` -//! For use with the wider Georust ecosystem, the primitives in the [`geo`](https://docs.rs/geo/latest/geo/#types) crate -//! can also be used. -//! -//! # (De)Serialization -//! Enable the `serde` feature for [serde](https://crates.io/crates/serde) support. -//! -//! # Mint compatibility with other crates -//! Enable the `mint` feature for -//! [`mint`](https://crates.io/crates/mint) support. See the -//! documentation on the [mint] module for an expample of an -//! integration with the -//! [`nalgebra`](https://crates.io/crates/nalgebra) crate. -#![deny(missing_docs)] -#![forbid(unsafe_code)] -#![cfg_attr(not(test), no_std)] - -extern crate alloc; - -mod aabb; -mod algorithm; -mod envelope; -mod node; -mod object; -mod params; -mod point; -pub mod primitives; -mod rtree; - -#[cfg(feature = "mint")] -pub mod mint; - -#[cfg(test)] -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::point::{Point, RTreeNum}; -pub use crate::rtree::RTree; - -pub use crate::algorithm::iterators; diff --git a/thirdparty/rstar/src/mint.rs b/thirdparty/rstar/src/mint.rs deleted file mode 100644 index 7d64266..0000000 --- a/thirdparty/rstar/src/mint.rs +++ /dev/null @@ -1,94 +0,0 @@ -//! [`mint`](https://crates.io/crates/mint) is a library for -//! interoperability between maths crates, for example, you may want -//! to use [nalgebra](https://crates.io/crates/nalgebra) types for -//! representing your points and _also_ use the same points with the -//! `rstar` library. -//! -//! Here is an example of how you might do that using `mint` types for -//! compatibility between the two libraries. Make sure to enable the -//! `mint` features on both the `nalgebra` and the `rstar` crates for -//! this to work. You will also need to depend on the -//! [`mint`](https://crates.io/crates/mint) crate. -//! -//! ``` -//! use rstar::RTree; -//! -//! let point1 = nalgebra::Point2::new(0.0, 0.0); -//! let point2 = nalgebra::Point2::new(1.0, 1.0); -//! -//! // First we have to convert the foreign points into the mint -//! // compatibility types before we can store them in the rtree -//! -//! let mint_point1: mint::Point2 = point1.into(); -//! let mint_point2: mint::Point2 = point2.into(); -//! -//! // Now we can use them with rtree structs and methods -//! let mut rtree = RTree::new(); -//! -//! rtree.insert(mint_point2); -//! -//! assert_eq!(rtree.nearest_neighbor(&mint_point1), Some(&mint_point2)); -//! ``` - -use crate::{Point, RTreeNum}; - -impl Point for mint::Point2 { - type Scalar = T; - - const DIMENSIONS: usize = 2; - - fn generate(mut generator: impl FnMut(usize) -> Self::Scalar) -> Self { - mint::Point2 { - x: generator(0), - y: generator(1), - } - } - - fn nth(&self, index: usize) -> Self::Scalar { - match index { - 0 => self.x, - 1 => self.y, - _ => unreachable!(), - } - } - - fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar { - match index { - 0 => &mut self.x, - 1 => &mut self.y, - _ => unreachable!(), - } - } -} - -impl Point for mint::Point3 { - type Scalar = T; - - const DIMENSIONS: usize = 3; - - fn generate(mut generator: impl FnMut(usize) -> Self::Scalar) -> Self { - mint::Point3 { - x: generator(0), - y: generator(1), - z: generator(2), - } - } - - fn nth(&self, index: usize) -> Self::Scalar { - match index { - 0 => self.x, - 1 => self.y, - 2 => self.z, - _ => unreachable!(), - } - } - - fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar { - match index { - 0 => &mut self.x, - 1 => &mut self.y, - 2 => &mut self.z, - _ => unreachable!(), - } - } -} diff --git a/thirdparty/rstar/src/node.rs b/thirdparty/rstar/src/node.rs deleted file mode 100644 index f455752..0000000 --- a/thirdparty/rstar/src/node.rs +++ /dev/null @@ -1,168 +0,0 @@ -use crate::envelope::Envelope; -use crate::object::RTreeObject; -use crate::params::RTreeParams; - -#[cfg(not(test))] -use alloc::vec::Vec; - -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr( - feature = "serde", - serde(bound( - serialize = "T: Serialize, T::Envelope: Serialize", - deserialize = "T: Deserialize<'de>, T::Envelope: Deserialize<'de>" - )) -)] - -/// An internal tree node. -/// -/// For most applications, using this type should not be required. -pub enum RTreeNode -where - T: RTreeObject, -{ - /// A leaf node, only containing the r-tree object - Leaf(T), - /// A parent node containing several child nodes - Parent(ParentNode), -} - -/// Represents an internal parent node. -/// -/// For most applications, using this type should not be required. Allows read access to this -/// node's envelope and its children. -#[derive(Debug, Clone)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct ParentNode -where - T: RTreeObject, -{ - pub(crate) children: Vec>, - pub(crate) envelope: T::Envelope, -} - -impl RTreeObject for RTreeNode -where - T: RTreeObject, -{ - type Envelope = T::Envelope; - - fn envelope(&self) -> Self::Envelope { - match self { - RTreeNode::Leaf(ref t) => t.envelope(), - RTreeNode::Parent(ref data) => data.envelope.clone(), - } - } -} - -#[doc(hidden)] -impl RTreeNode -where - T: RTreeObject, -{ - pub fn is_leaf(&self) -> bool { - match self { - RTreeNode::Leaf(..) => true, - RTreeNode::Parent(..) => false, - } - } -} - -impl ParentNode -where - T: RTreeObject, -{ - /// Returns this node's children - pub fn children(&self) -> &[RTreeNode] { - &self.children - } - - /// Returns the smallest envelope that encompasses all children. - pub fn envelope(&self) -> T::Envelope { - self.envelope.clone() - } - - pub(crate) fn new_root() -> Self - where - Params: RTreeParams, - { - ParentNode { - envelope: Envelope::new_empty(), - children: Vec::with_capacity(Params::MAX_SIZE + 1), - } - } - - pub(crate) fn new_parent(children: Vec>) -> Self { - let envelope = envelope_for_children(&children); - - ParentNode { envelope, children } - } - - #[cfg(test)] - #[allow(missing_docs)] - pub fn sanity_check(&self, check_max_size: bool) -> Option - where - Params: RTreeParams, - { - if self.children.is_empty() { - Some(0) - } else { - let mut result = None; - self.sanity_check_inner::(check_max_size, 1, &mut result); - result - } - } - - #[cfg(test)] - fn sanity_check_inner( - &self, - check_max_size: bool, - height: usize, - leaf_height: &mut Option, - ) where - Params: RTreeParams, - { - if height > 1 { - 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; - assert!(self.children.len() <= max_size); - } - - for child in &self.children { - match child { - RTreeNode::Leaf(ref t) => { - envelope.merge(&t.envelope()); - if let Some(ref leaf_height) = leaf_height { - assert_eq!(height, *leaf_height); - } else { - *leaf_height = Some(height); - } - } - RTreeNode::Parent(ref data) => { - envelope.merge(&data.envelope); - data.sanity_check_inner::(check_max_size, height + 1, leaf_height); - } - } - } - assert_eq!(self.envelope, envelope); - } -} - -pub fn envelope_for_children(children: &[RTreeNode]) -> T::Envelope -where - T: RTreeObject, -{ - let mut result = T::Envelope::new_empty(); - for child in children { - result.merge(&child.envelope()); - } - result -} diff --git a/thirdparty/rstar/src/object.rs b/thirdparty/rstar/src/object.rs deleted file mode 100644 index f388b51..0000000 --- a/thirdparty/rstar/src/object.rs +++ /dev/null @@ -1,233 +0,0 @@ -use crate::aabb::AABB; -use crate::envelope::Envelope; -use crate::point::{Point, PointExt}; - -/// An object that can be inserted into an r-tree. -/// -/// This trait must be implemented for any object to be inserted into an r-tree. -/// Some simple objects that already implement this trait can be found in the -/// [crate::primitives] module. -/// -/// The only property required of such an object is its [crate::Envelope]. -/// Most simply, this method should return the [axis aligned bounding box](AABB) -/// of the object. Other envelope types may be supported in the future. -/// -/// *Note*: It is a logic error if an object's envelope changes after insertion into -/// an r-tree. -/// -/// # Type parameters -/// `Envelope`: The object's envelope type. At the moment, only [AABB] is -/// available. -/// -/// # Example implementation -/// ``` -/// use rstar::{RTreeObject, AABB}; -/// -/// struct Player -/// { -/// name: String, -/// x_coordinate: f64, -/// y_coordinate: f64 -/// } -/// -/// impl RTreeObject for Player -/// { -/// type Envelope = AABB<[f64; 2]>; -/// -/// fn envelope(&self) -> Self::Envelope -/// { -/// AABB::from_point([self.x_coordinate, self.y_coordinate]) -/// } -/// } -/// -/// use rstar::RTree; -/// -/// let mut tree = RTree::new(); -/// -/// // Insert a few players... -/// tree.insert(Player { -/// name: "Forlorn Freeman".into(), -/// x_coordinate: 1., -/// y_coordinate: 0. -/// }); -/// tree.insert(Player { -/// name: "Sarah Croft".into(), -/// x_coordinate: 0.5, -/// y_coordinate: 0.5, -/// }); -/// tree.insert(Player { -/// name: "Geralt of Trivia".into(), -/// x_coordinate: 0., -/// y_coordinate: 2., -/// }); -/// -/// // Now we are ready to ask some questions! -/// let envelope = AABB::from_point([0.5, 0.5]); -/// let likely_sarah_croft = tree.locate_in_envelope(&envelope).next(); -/// println!("Found {:?} lurking around at (0.5, 0.5)!", likely_sarah_croft.unwrap().name); -/// # assert!(likely_sarah_croft.is_some()); -/// -/// let unit_square = AABB::from_corners([-1.0, -1.0], [1., 1.]); -/// for player in tree.locate_in_envelope(&unit_square) { -/// println!("And here is {:?} spelunking in the unit square.", player.name); -/// } -/// # assert_eq!(tree.locate_in_envelope(&unit_square).count(), 2); -/// ``` -pub trait RTreeObject { - /// The object's envelope type. Usually, [AABB] will be the right choice. - /// This type also defines the object's dimensionality. - type Envelope: Envelope; - - /// Returns the object's envelope. - /// - /// Usually, this will return the object's [axis aligned bounding box](AABB). - fn envelope(&self) -> Self::Envelope; -} - -/// Defines objects which can calculate their minimal distance to a point. -/// -/// This trait is most notably necessary for support of [nearest_neighbor](struct.RTree#method.nearest_neighbor) -/// queries. -/// -/// # Example -/// ``` -/// use rstar::{RTreeObject, PointDistance, AABB}; -/// -/// struct Circle -/// { -/// origin: [f32; 2], -/// radius: f32, -/// } -/// -/// impl RTreeObject for Circle { -/// type Envelope = AABB<[f32; 2]>; -/// -/// fn envelope(&self) -> Self::Envelope { -/// let corner_1 = [self.origin[0] - self.radius, self.origin[1] - self.radius]; -/// let corner_2 = [self.origin[0] + self.radius, self.origin[1] + self.radius]; -/// AABB::from_corners(corner_1, corner_2) -/// } -/// } -/// -/// impl PointDistance for Circle -/// { -/// fn distance_2(&self, point: &[f32; 2]) -> f32 -/// { -/// let d_x = self.origin[0] - point[0]; -/// let d_y = self.origin[1] - point[1]; -/// let distance_to_origin = (d_x * d_x + d_y * d_y).sqrt(); -/// let distance_to_ring = distance_to_origin - self.radius; -/// let distance_to_circle = f32::max(0.0, distance_to_ring); -/// // We must return the squared distance! -/// distance_to_circle * distance_to_circle -/// } -/// -/// // This implementation is not required but more efficient since it -/// // omits the calculation of a square root -/// fn contains_point(&self, point: &[f32; 2]) -> bool -/// { -/// let d_x = self.origin[0] - point[0]; -/// let d_y = self.origin[1] - point[1]; -/// let distance_to_origin_2 = (d_x * d_x + d_y * d_y); -/// let radius_2 = self.radius * self.radius; -/// distance_to_origin_2 <= radius_2 -/// } -/// } -/// -/// -/// let circle = Circle { -/// origin: [1.0, 0.0], -/// radius: 1.0, -/// }; -/// -/// assert_eq!(circle.distance_2(&[-1.0, 0.0]), 1.0); -/// assert_eq!(circle.distance_2(&[-2.0, 0.0]), 4.0); -/// assert!(circle.contains_point(&[1.0, 0.0])); -/// ``` -pub trait PointDistance: RTreeObject { - /// Returns the squared distance between an object and a point. - /// - /// # Notes - /// - While euclidean distance will be the correct choice for most use cases, any distance metric - /// fulfilling the [usual axioms](https://en.wikipedia.org/wiki/Metric_space) - /// can be used when implementing this method - /// - Implementers **must** ensure that the distance metric used matches that of [crate::Envelope::distance_2] - fn distance_2( - &self, - point: &::Point, - ) -> <::Point as Point>::Scalar; - - /// Returns `true` if a point is contained within this object. - /// - /// By default, any point returning a `distance_2` less than or equal to zero is considered to be - /// contained within `self`. Changing this default behavior is advised if calculating the squared distance - /// is more computationally expensive than a point containment check. - fn contains_point(&self, point: &::Point) -> bool { - self.distance_2(point) <= num_traits::zero() - } - - /// Returns the squared distance to this object, or `None` if the distance - /// is larger than a given maximum value. - /// - /// Some algorithms only need to know an object's distance - /// if it is less than or equal to a maximum value. In these cases, it may be - /// faster to calculate a lower bound of the distance first and returning - /// early if the object cannot be closer than the given maximum. - /// - /// The provided default implementation will use the distance to the object's - /// envelope as a lower bound. - /// - /// If performance is critical and the object's distance calculation is fast, - /// it may be beneficial to overwrite this implementation. - fn distance_2_if_less_or_equal( - &self, - point: &::Point, - max_distance_2: <::Point as Point>::Scalar, - ) -> Option<<::Point as Point>::Scalar> { - let envelope_distance = self.envelope().distance_2(point); - if envelope_distance <= max_distance_2 { - let distance_2 = self.distance_2(point); - if distance_2 <= max_distance_2 { - return Some(distance_2); - } - } - None - } -} - -impl

RTreeObject for P -where - P: Point, -{ - type Envelope = AABB

; - - fn envelope(&self) -> AABB

{ - AABB::from_point(self.clone()) - } -} - -impl

PointDistance for P -where - P: Point, -{ - fn distance_2(&self, point: &P) -> P::Scalar { - ::distance_2(self, point) - } - - fn contains_point(&self, point: &::Point) -> bool { - self == point - } - - fn distance_2_if_less_or_equal( - &self, - point: &::Point, - max_distance_2: <::Point as Point>::Scalar, - ) -> Option { - let distance_2 = ::distance_2(self, point); - if distance_2 <= max_distance_2 { - Some(distance_2) - } else { - None - } - } -} diff --git a/thirdparty/rstar/src/params.rs b/thirdparty/rstar/src/params.rs deleted file mode 100644 index 03c2777..0000000 --- a/thirdparty/rstar/src/params.rs +++ /dev/null @@ -1,116 +0,0 @@ -use crate::algorithm::rstar::RStarInsertionStrategy; -use crate::{Envelope, Point, RTree, RTreeObject}; - -/// Defines static parameters for an r-tree. -/// -/// Internally, an r-tree contains several nodes, similar to a b-tree. These parameters change -/// the size of these nodes and can be used to fine-tune the tree's performance. -/// -/// # Example -/// ``` -/// use rstar::{RTreeParams, RTree, RStarInsertionStrategy}; -/// -/// // 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(); -/// // 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); -/// # } -/// ``` -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; - - /// The insertion strategy which is used when calling [RTree::insert]. - type DefaultInsertionStrategy: InsertionStrategy; -} - -/// The default parameters used when creating an r-tree without specific parameters. -#[derive(Clone, Copy, PartialEq, Eq, Default)] -pub struct DefaultParams; - -impl RTreeParams for DefaultParams { - const MIN_SIZE: usize = 3; - const MAX_SIZE: usize = 6; - const REINSERTION_COUNT: usize = 2; - type DefaultInsertionStrategy = RStarInsertionStrategy; -} - -/// 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; -} - -pub fn verify_parameters() { - assert!( - P::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 - ); - - 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 dimension = ::Point::DIMENSIONS; - assert!( - dimension > 1, - "Point dimension too small - must be at least 2" - ); -} diff --git a/thirdparty/rstar/src/point.rs b/thirdparty/rstar/src/point.rs deleted file mode 100644 index a6839dd..0000000 --- a/thirdparty/rstar/src/point.rs +++ /dev/null @@ -1,437 +0,0 @@ -use core::fmt::Debug; -use num_traits::{Bounded, Num, Signed, Zero}; - -/// Defines a number type that is compatible with rstar. -/// -/// rstar works out of the box with the following standard library types: -/// - i8, i16, i32, i64, i128, isize -/// - [Wrapping](core::num::Wrapping) versions of the above -/// - f32, f64 -/// -/// This type cannot be implemented directly. Instead, it is required to implement -/// all required traits from the `num_traits` crate. -/// -/// # Example -/// ``` -/// # extern crate num_traits; -/// use num_traits::{Bounded, Num, Signed}; -/// -/// #[derive(Clone, Copy, PartialEq, PartialOrd, Debug)] -/// struct MyFancyNumberType(f32); -/// -/// impl num_traits::Bounded for MyFancyNumberType { -/// // ... details hidden ... -/// # fn min_value() -> Self { Self(Bounded::min_value()) } -/// # -/// # fn max_value() -> Self { Self(Bounded::max_value()) } -/// } -/// -/// impl Signed for MyFancyNumberType { -/// // ... details hidden ... -/// # fn abs(&self) -> Self { unimplemented!() } -/// # -/// # fn abs_sub(&self, other: &Self) -> Self { unimplemented!() } -/// # -/// # fn signum(&self) -> Self { unimplemented!() } -/// # -/// # fn is_positive(&self) -> bool { unimplemented!() } -/// # -/// # fn is_negative(&self) -> bool { unimplemented!() } -/// } -/// -/// impl Num for MyFancyNumberType { -/// // ... details hidden ... -/// # type FromStrRadixErr = num_traits::ParseFloatError; -/// # fn from_str_radix(str: &str, radix: u32) -> Result { unimplemented!() } -/// } -/// -/// // Lots of traits are still missing to make the above code compile, but -/// // let's assume they're implemented. `MyFancyNumberType` type now readily implements -/// // RTreeNum and can be used with r-trees: -/// # fn main() { -/// use rstar::RTree; -/// let mut rtree = RTree::new(); -/// rtree.insert([MyFancyNumberType(0.0), MyFancyNumberType(0.0)]); -/// # } -/// -/// # impl num_traits::Zero for MyFancyNumberType { -/// # fn zero() -> Self { unimplemented!() } -/// # fn is_zero(&self) -> bool { unimplemented!() } -/// # } -/// # -/// # impl num_traits::One for MyFancyNumberType { -/// # fn one() -> Self { unimplemented!() } -/// # } -/// # -/// # impl core::ops::Mul for MyFancyNumberType { -/// # type Output = Self; -/// # fn mul(self, rhs: Self) -> Self { unimplemented!() } -/// # } -/// # -/// # impl core::ops::Add for MyFancyNumberType { -/// # type Output = Self; -/// # fn add(self, rhs: Self) -> Self { unimplemented!() } -/// # } -/// # -/// # impl core::ops::Sub for MyFancyNumberType { -/// # type Output = Self; -/// # fn sub(self, rhs: Self) -> Self { unimplemented!() } -/// # } -/// # -/// # impl core::ops::Div for MyFancyNumberType { -/// # type Output = Self; -/// # fn div(self, rhs: Self) -> Self { unimplemented!() } -/// # } -/// # -/// # impl core::ops::Rem for MyFancyNumberType { -/// # type Output = Self; -/// # fn rem(self, rhs: Self) -> Self { unimplemented!() } -/// # } -/// # -/// # impl core::ops::Neg for MyFancyNumberType { -/// # type Output = Self; -/// # fn neg(self) -> Self { unimplemented!() } -/// # } -/// # -/// ``` -/// -pub trait RTreeNum: Bounded + Num + Clone + Copy + Signed + PartialOrd + Debug {} - -impl RTreeNum for S where S: Bounded + Num + Clone + Copy + Signed + PartialOrd + Debug {} - -/// Defines a point type that is compatible with rstar. -/// -/// This trait should be used for interoperability with other point types, not to define custom objects -/// that can be inserted into r-trees. Use [`crate::RTreeObject`] or -/// [`crate::primitives::GeomWithData`] instead. -/// This trait defines points, not points with metadata. -/// -/// `Point` is implemented out of the box for arrays like `[f32; 2]` or `[f64; 7]` (for any number of dimensions), -/// and for tuples like `(int, int)` and `(f64, f64, f64)` so tuples with only elements of the same type (up to dimension 9). -/// -/// -/// # Implementation example -/// Supporting a custom point type might look like this: -/// -/// ``` -/// use rstar::Point; -/// -/// #[derive(Copy, Clone, PartialEq, Debug)] -/// struct IntegerPoint -/// { -/// x: i32, -/// y: i32 -/// } -/// -/// impl Point for IntegerPoint -/// { -/// type Scalar = i32; -/// const DIMENSIONS: usize = 2; -/// -/// fn generate(mut generator: impl FnMut(usize) -> Self::Scalar) -> Self -/// { -/// IntegerPoint { -/// x: generator(0), -/// y: generator(1) -/// } -/// } -/// -/// fn nth(&self, index: usize) -> Self::Scalar -/// { -/// match index { -/// 0 => self.x, -/// 1 => self.y, -/// _ => unreachable!() -/// } -/// } -/// -/// fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar -/// { -/// match index { -/// 0 => &mut self.x, -/// 1 => &mut self.y, -/// _ => unreachable!() -/// } -/// } -/// } -/// ``` -pub trait Point: Clone + PartialEq + Debug { - /// The number type used by this point type. - type Scalar: RTreeNum; - - /// The number of dimensions of this point type. - const DIMENSIONS: usize; - - /// Creates a new point value with given values for each dimension. - /// - /// The value that each dimension should be initialized with is given by the parameter `generator`. - /// Calling `generator(n)` returns the value of dimension `n`, `n` will be in the range `0 .. Self::DIMENSIONS`, - /// and will be called with values of `n` in ascending order. - fn generate(generator: impl FnMut(usize) -> Self::Scalar) -> Self; - - /// Returns a single coordinate of this point. - /// - /// Returns the coordinate indicated by `index`. `index` is always smaller than `Self::DIMENSIONS`. - fn nth(&self, index: usize) -> Self::Scalar; - - /// Mutable variant of [nth](#methods.nth). - fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar; -} - -impl PointExt for T where T: Point {} - -/// Utility functions for Point -pub trait PointExt: Point { - /// Returns a new Point with all components set to zero. - fn new() -> Self { - Self::from_value(Zero::zero()) - } - - /// Applies `f` to each pair of components of `self` and `other`. - fn component_wise( - &self, - other: &Self, - mut f: impl FnMut(Self::Scalar, Self::Scalar) -> Self::Scalar, - ) -> Self { - Self::generate(|i| f(self.nth(i), other.nth(i))) - } - - /// Returns whether all pairs of components of `self` and `other` pass test closure `f`. Short circuits if any result is false. - fn all_component_wise( - &self, - other: &Self, - mut f: impl FnMut(Self::Scalar, Self::Scalar) -> bool, - ) -> bool { - (0..Self::DIMENSIONS).all(|i| f(self.nth(i), other.nth(i))) - } - - /// Returns the dot product of `self` and `rhs`. - fn dot(&self, rhs: &Self) -> Self::Scalar { - self.component_wise(rhs, |l, r| l * r) - .fold(Zero::zero(), |acc, val| acc + val) - } - - /// Folds (aka reduces or injects) the Point component wise using `f` and returns the result. - /// fold() takes two arguments: an initial value, and a closure with two arguments: an 'accumulator', and the value of the current component. - /// The closure returns the value that the accumulator should have for the next iteration. - /// - /// The `start_value` is the value the accumulator will have on the first call of the closure. - /// - /// After applying the closure to every component of the Point, fold() returns the accumulator. - fn fold(&self, start_value: T, mut f: impl FnMut(T, Self::Scalar) -> T) -> T { - (0..Self::DIMENSIONS).fold(start_value, |accumulated, i| f(accumulated, self.nth(i))) - } - - /// Returns a Point with every component set to `value`. - fn from_value(value: Self::Scalar) -> Self { - Self::generate(|_| value) - } - - /// Returns a Point with each component set to the smallest of each component pair of `self` and `other`. - fn min_point(&self, other: &Self) -> Self { - self.component_wise(other, min_inline) - } - - /// Returns a Point with each component set to the biggest of each component pair of `self` and `other`. - fn max_point(&self, other: &Self) -> Self { - self.component_wise(other, max_inline) - } - - /// Returns the squared length of this Point as if it was a vector. - fn length_2(&self) -> Self::Scalar { - self.fold(Zero::zero(), |acc, cur| cur * cur + acc) - } - - /// Substracts `other` from `self` component wise. - fn sub(&self, other: &Self) -> Self { - self.component_wise(other, |l, r| l - r) - } - - /// Adds `other` to `self` component wise. - fn add(&self, other: &Self) -> Self { - self.component_wise(other, |l, r| l + r) - } - - /// Multiplies `self` with `scalar` component wise. - fn mul(&self, scalar: Self::Scalar) -> Self { - self.map(|coordinate| coordinate * scalar) - } - - /// Applies `f` to `self` component wise. - fn map(&self, mut f: impl FnMut(Self::Scalar) -> Self::Scalar) -> Self { - Self::generate(|i| f(self.nth(i))) - } - - /// Returns the squared distance between `self` and `other`. - fn distance_2(&self, other: &Self) -> Self::Scalar { - self.sub(other).length_2() - } -} - -#[inline] -pub fn min_inline(a: S, b: S) -> S -where - S: RTreeNum, -{ - if a < b { - a - } else { - b - } -} - -#[inline] -pub fn max_inline(a: S, b: S) -> S -where - S: RTreeNum, -{ - if a > b { - a - } else { - b - } -} - -impl Point for [S; N] -where - S: RTreeNum, -{ - type Scalar = S; - - const DIMENSIONS: usize = N; - - fn generate(mut generator: impl FnMut(usize) -> S) -> Self { - // The same implementation used in std::array::from_fn - // Since this is a const generic it gets unrolled - let mut idx = 0; - [(); N].map(|_| { - let res = generator(idx); - idx += 1; - res - }) - } - - #[inline] - fn nth(&self, index: usize) -> Self::Scalar { - self[index] - } - - #[inline] - fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar { - &mut self[index] - } -} - -macro_rules! count_exprs { - () => (0); - ($head:expr) => (1); - ($head:expr, $($tail:expr),*) => (1 + count_exprs!($($tail),*)); -} - -macro_rules! fixed_type { - ($expr:expr, $type:ty) => { - $type - }; -} - -macro_rules! impl_point_for_tuple { - ($($index:expr => $name:ident),+) => { - impl Point for ($(fixed_type!($index, S),)+) - where - S: RTreeNum - { - type Scalar = S; - - const DIMENSIONS: usize = count_exprs!($($index),*); - - fn generate(mut generator: impl FnMut(usize) -> S) -> Self { - ($(generator($index),)+) - } - - #[inline] - fn nth(&self, index: usize) -> Self::Scalar { - let ($($name,)+) = self; - - match index { - $($index => *$name,)+ - _ => unreachable!("index {} out of bounds for tuple", index), - } - } - - #[inline] - fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar { - let ($($name,)+) = self; - - match index { - $($index => $name,)+ - _ => unreachable!("index {} out of bounds for tuple", index), - } - } - } - }; -} - -impl_point_for_tuple!(0 => a); -impl_point_for_tuple!(0 => a, 1 => b); -impl_point_for_tuple!(0 => a, 1 => b, 2 => c); -impl_point_for_tuple!(0 => a, 1 => b, 2 => c, 3 => d); -impl_point_for_tuple!(0 => a, 1 => b, 2 => c, 3 => d, 4 => e); -impl_point_for_tuple!(0 => a, 1 => b, 2 => c, 3 => d, 4 => e, 5 => f); -impl_point_for_tuple!(0 => a, 1 => b, 2 => c, 3 => d, 4 => e, 5 => f, 6 => g); -impl_point_for_tuple!(0 => a, 1 => b, 2 => c, 3 => d, 4 => e, 5 => f, 6 => g, 7 => h); -impl_point_for_tuple!(0 => a, 1 => b, 2 => c, 3 => d, 4 => e, 5 => f, 6 => g, 7 => h, 8 => i); -impl_point_for_tuple!(0 => a, 1 => b, 2 => c, 3 => d, 4 => e, 5 => f, 6 => g, 7 => h, 8 => i, 9 => j); - -#[cfg(test)] -mod tests { - use super::*; - use core::num::Wrapping; - - #[test] - fn test_types() { - fn assert_impl_rtreenum() {} - - assert_impl_rtreenum::(); - assert_impl_rtreenum::(); - assert_impl_rtreenum::(); - assert_impl_rtreenum::(); - assert_impl_rtreenum::(); - assert_impl_rtreenum::(); - assert_impl_rtreenum::>(); - assert_impl_rtreenum::>(); - assert_impl_rtreenum::>(); - assert_impl_rtreenum::>(); - assert_impl_rtreenum::>(); - assert_impl_rtreenum::>(); - assert_impl_rtreenum::(); - assert_impl_rtreenum::(); - } - - macro_rules! test_tuple_configuration { - ($($index:expr),*) => { - let a = ($($index),*); - $(assert_eq!(a.nth($index), $index));* - } - } - - #[test] - fn test_tuples() { - // Test a couple of simple cases - let simple_int = (0, 1, 2); - assert_eq!(simple_int.nth(2), 2); - let simple_float = (0.5, 0.67, 1234.56); - assert_eq!(simple_float.nth(2), 1234.56); - let long_int = (0, 1, 2, 3, 4, 5, 6, 7, 8); - assert_eq!(long_int.nth(8), 8); - - // Generate the code to test every nth function for every Tuple length - test_tuple_configuration!(0, 1); - test_tuple_configuration!(0, 1, 2); - test_tuple_configuration!(0, 1, 2, 3); - test_tuple_configuration!(0, 1, 2, 3, 4); - test_tuple_configuration!(0, 1, 2, 3, 4, 5); - test_tuple_configuration!(0, 1, 2, 3, 4, 5, 6); - test_tuple_configuration!(0, 1, 2, 3, 4, 5, 6, 7); - test_tuple_configuration!(0, 1, 2, 3, 4, 5, 6, 7, 8); - } -} diff --git a/thirdparty/rstar/src/primitives/cached_envelope.rs b/thirdparty/rstar/src/primitives/cached_envelope.rs deleted file mode 100644 index ae040f3..0000000 --- a/thirdparty/rstar/src/primitives/cached_envelope.rs +++ /dev/null @@ -1,127 +0,0 @@ -use crate::envelope::Envelope; -use crate::object::PointDistance; -use crate::{object::RTreeObject, point::Point}; -use core::ops::Deref; - -/// An [RTreeObject] with an inner geometry whose envelope is cached to improve efficiency. -/// -/// For complex geometry like polygons, computing the envelope can become a bottleneck during -/// tree construction and querying. Hence this combinator computes it once during creation, -/// stores it and then returns a copy. -/// -/// **Note:** the container itself implements [RTreeObject] and inner geometry `T` can be -/// accessed via an implementation of `Deref`. -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct CachedEnvelope { - inner: T, - cached_env: T::Envelope, -} - -impl RTreeObject for CachedEnvelope -where - T::Envelope: Clone, -{ - type Envelope = T::Envelope; - - fn envelope(&self) -> Self::Envelope { - self.cached_env.clone() - } -} - -impl PointDistance for CachedEnvelope { - fn distance_2( - &self, - point: &::Point, - ) -> <::Point as Point>::Scalar { - self.inner.distance_2(point) - } - - fn contains_point(&self, p: &::Point) -> bool { - self.inner.contains_point(p) - } - - fn distance_2_if_less_or_equal( - &self, - point: &::Point, - max_distance_2: <::Point as Point>::Scalar, - ) -> Option<<::Point as Point>::Scalar> { - self.inner - .distance_2_if_less_or_equal(point, max_distance_2) - } -} - -impl CachedEnvelope { - /// Create a new [CachedEnvelope] struct using the provided geometry. - pub fn new(inner: T) -> Self { - let cached_env = inner.envelope(); - - Self { inner, cached_env } - } -} - -impl Deref for CachedEnvelope { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -#[cfg(test)] -mod test { - use super::CachedEnvelope; - use crate::object::PointDistance; - use crate::primitives::GeomWithData; - - use approx::*; - - use crate::{primitives::Line, RTree}; - - #[test] - fn container_in_rtree() { - let line_1 = CachedEnvelope::new(Line::new([0.0, 0.0], [1.0, 1.0])); - let line_2 = CachedEnvelope::new(Line::new([0.0, 0.0], [-1.0, 1.0])); - let tree = RTree::bulk_load(vec![line_1, line_2]); - - assert!(tree.contains(&line_1)); - } - - #[test] - fn container_edge_distance() { - let edge = CachedEnvelope::new(Line::new([0.5, 0.5], [0.5, 2.0])); - - assert_abs_diff_eq!(edge.distance_2(&[0.5, 0.5]), 0.0); - assert_abs_diff_eq!(edge.distance_2(&[0.0, 0.5]), 0.5 * 0.5); - assert_abs_diff_eq!(edge.distance_2(&[0.5, 1.0]), 0.0); - assert_abs_diff_eq!(edge.distance_2(&[0.0, 0.0]), 0.5); - assert_abs_diff_eq!(edge.distance_2(&[0.0, 1.0]), 0.5 * 0.5); - assert_abs_diff_eq!(edge.distance_2(&[1.0, 1.0]), 0.5 * 0.5); - assert_abs_diff_eq!(edge.distance_2(&[1.0, 3.0]), 0.5 * 0.5 + 1.0); - } - - #[test] - fn container_length_2() { - let line = CachedEnvelope::new(Line::new([1, -1], [5, 5])); - - assert_eq!(line.length_2(), 16 + 36); - } - - #[test] - fn container_nearest_neighbour() { - let mut lines = RTree::new(); - lines.insert(GeomWithData::new( - CachedEnvelope::new(Line::new([0.0, 0.0], [1.0, 1.0])), - "Line A", - )); - lines.insert(GeomWithData::new( - CachedEnvelope::new(Line::new([0.0, 0.0], [-1.0, 1.0])), - "Line B", - )); - let my_location = [0.0, 0.0]; - // Now find the closest line - let place = lines.nearest_neighbor(&my_location).unwrap(); - - assert_eq!(place.data, "Line A"); - } -} diff --git a/thirdparty/rstar/src/primitives/geom_with_data.rs b/thirdparty/rstar/src/primitives/geom_with_data.rs deleted file mode 100644 index 5046f5e..0000000 --- a/thirdparty/rstar/src/primitives/geom_with_data.rs +++ /dev/null @@ -1,136 +0,0 @@ -use crate::envelope::Envelope; -use crate::object::PointDistance; -use crate::{object::RTreeObject, point::Point}; - -/// An [RTreeObject] with a geometry and some associated data that can be inserted into an r-tree. -/// -/// Often, adding metadata (like a database ID) to a geometry is required before adding it -/// into an r-tree. This struct removes some of the boilerplate required to do so. -/// -/// **Note:** while the container itself implements [RTreeObject], you will have to go through its -/// [`geom`][Self::geom] method in order to access geometry-specific methods. -/// -/// # Example -/// ``` -/// use rstar::{RTree, PointDistance}; -/// use rstar::primitives::GeomWithData; -/// -/// type RestaurantLocation = GeomWithData<[f64; 2], &'static str>; -/// -/// let mut restaurants = RTree::new(); -/// restaurants.insert(RestaurantLocation::new([0.3, 0.2], "Pete's Pizza Place")); -/// restaurants.insert(RestaurantLocation::new([-0.8, 0.0], "The Great Steak")); -/// restaurants.insert(RestaurantLocation::new([0.2, -0.2], "Fishy Fortune")); -/// -/// let my_location = [0.0, 0.0]; -/// -/// // Now find the closest restaurant! -/// let place = restaurants.nearest_neighbor(&my_location).unwrap(); -/// println!("Let's go to {}", place.data); -/// println!("It's really close, only {} miles", place.distance_2(&my_location)); -/// ``` -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct GeomWithData { - geom: R, - /// Data to be associated with the geometry being stored in the [`RTree`](crate::RTree). - pub data: T, -} - -impl RTreeObject for GeomWithData { - type Envelope = R::Envelope; - - fn envelope(&self) -> Self::Envelope { - self.geom.envelope() - } -} - -impl PointDistance for GeomWithData { - fn distance_2( - &self, - point: &::Point, - ) -> <::Point as Point>::Scalar { - self.geom.distance_2(point) - } - - fn contains_point(&self, p: &::Point) -> bool { - self.geom.contains_point(p) - } - - fn distance_2_if_less_or_equal( - &self, - point: &::Point, - max_distance_2: <::Point as Point>::Scalar, - ) -> Option<<::Point as Point>::Scalar> { - self.geom.distance_2_if_less_or_equal(point, max_distance_2) - } -} - -impl GeomWithData { - /// Create a new [GeomWithData] struct using the provided geometry and data. - pub fn new(geom: R, data: T) -> Self { - Self { geom, data } - } - - /// Get a reference to the container's geometry. - pub fn geom(&self) -> &R { - &self.geom - } -} - -#[cfg(test)] -mod test { - use super::GeomWithData; - use crate::object::PointDistance; - - use approx::*; - - use crate::{primitives::Line, RTree}; - - #[test] - fn container_in_rtree() { - let line_1 = GeomWithData::new(Line::new([0.0, 0.0], [1.0, 1.0]), ()); - let line_2 = GeomWithData::new(Line::new([0.0, 0.0], [-1.0, 1.0]), ()); - let tree = RTree::bulk_load(vec![line_1, line_2]); - - assert!(tree.contains(&line_1)); - } - - #[test] - fn container_edge_distance() { - let edge = GeomWithData::new(Line::new([0.5, 0.5], [0.5, 2.0]), 1usize); - - assert_abs_diff_eq!(edge.distance_2(&[0.5, 0.5]), 0.0); - assert_abs_diff_eq!(edge.distance_2(&[0.0, 0.5]), 0.5 * 0.5); - assert_abs_diff_eq!(edge.distance_2(&[0.5, 1.0]), 0.0); - assert_abs_diff_eq!(edge.distance_2(&[0.0, 0.0]), 0.5); - assert_abs_diff_eq!(edge.distance_2(&[0.0, 1.0]), 0.5 * 0.5); - assert_abs_diff_eq!(edge.distance_2(&[1.0, 1.0]), 0.5 * 0.5); - assert_abs_diff_eq!(edge.distance_2(&[1.0, 3.0]), 0.5 * 0.5 + 1.0); - } - - #[test] - fn container_length_2() { - let line = GeomWithData::new(Line::new([1, -1], [5, 5]), 1usize); - - assert_eq!(line.geom().length_2(), 16 + 36); - } - - #[test] - fn container_nearest_neighbour() { - let mut lines = RTree::new(); - lines.insert(GeomWithData::new( - Line::new([0.0, 0.0], [1.0, 1.0]), - "Line A", - )); - lines.insert(GeomWithData::new( - Line::new([0.0, 0.0], [-1.0, 1.0]), - "Line B", - )); - let my_location = [0.0, 0.0]; - // Now find the closest line - let place = lines.nearest_neighbor(&my_location).unwrap(); - - assert_eq!(place.data, "Line A"); - } -} diff --git a/thirdparty/rstar/src/primitives/line.rs b/thirdparty/rstar/src/primitives/line.rs deleted file mode 100644 index 8999268..0000000 --- a/thirdparty/rstar/src/primitives/line.rs +++ /dev/null @@ -1,142 +0,0 @@ -use crate::aabb::AABB; -use crate::envelope::Envelope; -use crate::object::PointDistance; -use crate::object::RTreeObject; -use crate::point::{Point, PointExt}; -use num_traits::{One, Zero}; - -/// A line defined by a start and and end point. -/// -/// This struct can be inserted directly into an r-tree. -/// # Type parameters -/// `P`: The line's [Point] type. -/// -/// # Example -/// ``` -/// use rstar::primitives::Line; -/// use rstar::{RTree, RTreeObject}; -/// -/// let line_1 = Line::new([0.0, 0.0], [1.0, 1.0]); -/// let line_2 = Line::new([0.0, 0.0], [-1.0, 1.0]); -/// let tree = RTree::bulk_load(vec![line_1, line_2]); -/// -/// assert!(tree.contains(&line_1)); -/// ``` -#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Line

-where - P: Point, -{ - /// The line's start point - pub from: P, - /// The line's end point. - pub to: P, -} - -impl

Line

-where - P: Point, -{ - /// Creates a new line between two points. - pub fn new(from: P, to: P) -> Self { - Line { from, to } - } -} - -impl

RTreeObject for Line

-where - P: Point, -{ - type Envelope = AABB

; - - fn envelope(&self) -> Self::Envelope { - AABB::from_corners(self.from.clone(), self.to.clone()) - } -} - -impl

Line

-where - P: Point, -{ - /// Returns the squared length of this line. - /// - /// # Example - /// ``` - /// use rstar::primitives::Line; - /// - /// let line = Line::new([3, 3], [7, 6]); - /// assert_eq!(line.length_2(), 25); - /// ``` - pub fn length_2(&self) -> P::Scalar { - self.from.sub(&self.to).length_2() - } - - fn project_point(&self, query_point: &P) -> P::Scalar { - let (ref p1, ref p2) = (self.from.clone(), self.to.clone()); - let dir = p2.sub(p1); - query_point.sub(p1).dot(&dir) / dir.length_2() - } - - /// Returns the nearest point on this line relative to a given point. - /// - /// # Example - /// ``` - /// use rstar::primitives::Line; - /// - /// let line = Line::new([0.0, 0.0], [1., 1.]); - /// assert_eq!(line.nearest_point(&[0.0, 0.0]), [0.0, 0.0]); - /// assert_eq!(line.nearest_point(&[1.0, 0.0]), [0.5, 0.5]); - /// assert_eq!(line.nearest_point(&[10., 12.]), [1.0, 1.0]); - /// ``` - pub fn nearest_point(&self, query_point: &P) -> P { - let (p1, p2) = (self.from.clone(), self.to.clone()); - let dir = p2.sub(&p1); - let s = self.project_point(query_point); - if P::Scalar::zero() < s && s < One::one() { - p1.add(&dir.mul(s)) - } else if s <= P::Scalar::zero() { - p1 - } else { - p2 - } - } -} - -impl

PointDistance for Line

-where - P: Point, -{ - fn distance_2( - &self, - point: &::Point, - ) -> <::Point as Point>::Scalar { - self.nearest_point(point).sub(point).length_2() - } -} - -#[cfg(test)] -mod test { - use super::Line; - use crate::object::PointDistance; - use approx::*; - - #[test] - fn edge_distance() { - let edge = Line::new([0.5, 0.5], [0.5, 2.0]); - - assert_abs_diff_eq!(edge.distance_2(&[0.5, 0.5]), 0.0); - assert_abs_diff_eq!(edge.distance_2(&[0.0, 0.5]), 0.5 * 0.5); - assert_abs_diff_eq!(edge.distance_2(&[0.5, 1.0]), 0.0); - assert_abs_diff_eq!(edge.distance_2(&[0.0, 0.0]), 0.5); - assert_abs_diff_eq!(edge.distance_2(&[0.0, 1.0]), 0.5 * 0.5); - assert_abs_diff_eq!(edge.distance_2(&[1.0, 1.0]), 0.5 * 0.5); - assert_abs_diff_eq!(edge.distance_2(&[1.0, 3.0]), 0.5 * 0.5 + 1.0); - } - - #[test] - fn length_2() { - let line = Line::new([1, -1], [5, 5]); - assert_eq!(line.length_2(), 16 + 36); - } -} diff --git a/thirdparty/rstar/src/primitives/mod.rs b/thirdparty/rstar/src/primitives/mod.rs deleted file mode 100644 index 27e1ebc..0000000 --- a/thirdparty/rstar/src/primitives/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -//! Contains primitives ready for insertion into an r-tree. - -mod cached_envelope; -mod geom_with_data; -mod line; -mod object_ref; -mod point_with_data; -mod rectangle; - -pub use self::cached_envelope::CachedEnvelope; -pub use self::geom_with_data::GeomWithData; -pub use self::line::Line; -pub use self::object_ref::ObjectRef; -pub use self::point_with_data::PointWithData; -pub use self::rectangle::Rectangle; diff --git a/thirdparty/rstar/src/primitives/object_ref.rs b/thirdparty/rstar/src/primitives/object_ref.rs deleted file mode 100644 index 0608d81..0000000 --- a/thirdparty/rstar/src/primitives/object_ref.rs +++ /dev/null @@ -1,62 +0,0 @@ -use crate::envelope::Envelope; -use crate::object::PointDistance; -use crate::{object::RTreeObject, point::Point}; -use core::ops::Deref; - -/// An [RTreeObject] that is a possibly short-lived reference to another object. -/// -/// Sometimes it can be useful to build an [RTree] that does not own its constituent -/// objects but references them from elsewhere. Wrapping the bare references with this -/// combinator makes this possible. -/// -/// **Note:** the wrapper implements [RTreeObject] and referenced object `T` can be -/// accessed via an implementation of `Deref`. -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct ObjectRef<'a, T: RTreeObject> { - inner: &'a T, -} - -impl<'a, T: RTreeObject> RTreeObject for ObjectRef<'a, T> { - type Envelope = T::Envelope; - - fn envelope(&self) -> Self::Envelope { - self.inner.envelope() - } -} - -impl<'a, T: PointDistance> PointDistance for ObjectRef<'a, T> { - fn distance_2( - &self, - point: &::Point, - ) -> <::Point as Point>::Scalar { - self.inner.distance_2(point) - } - - fn contains_point(&self, p: &::Point) -> bool { - self.inner.contains_point(p) - } - - fn distance_2_if_less_or_equal( - &self, - point: &::Point, - max_distance_2: <::Point as Point>::Scalar, - ) -> Option<<::Point as Point>::Scalar> { - self.inner - .distance_2_if_less_or_equal(point, max_distance_2) - } -} - -impl<'a, T: RTreeObject> ObjectRef<'a, T> { - /// Create a new [ObjectRef] struct using the object. - pub fn new(inner: &'a T) -> Self { - Self { inner } - } -} - -impl<'a, T: RTreeObject> Deref for ObjectRef<'a, T> { - type Target = T; - - fn deref(&self) -> &Self::Target { - self.inner - } -} diff --git a/thirdparty/rstar/src/primitives/point_with_data.rs b/thirdparty/rstar/src/primitives/point_with_data.rs deleted file mode 100644 index 9ba54a3..0000000 --- a/thirdparty/rstar/src/primitives/point_with_data.rs +++ /dev/null @@ -1,72 +0,0 @@ -use crate::{Point, PointDistance, RTreeObject, AABB}; - -/// A point with some associated data that can be inserted into an r-tree. -/// -/// **Note**: `PointWithData` has been deprecated in favour of [`GeomWithData`](crate::primitives::GeomWithData) -/// -/// Often, adding metadata (like a database index) to a point is required before adding them -/// into an r-tree. This struct removes some of the boilerplate required to do so. -/// -/// # Example -/// ``` -/// use rstar::{RTree, PointDistance}; -/// use rstar::primitives::PointWithData; -/// -/// type RestaurantLocation = PointWithData<&'static str, [f64; 2]>; -/// -/// let mut restaurants = RTree::new(); -/// restaurants.insert(RestaurantLocation::new("Pete's Pizza Place", [0.3, 0.2])); -/// restaurants.insert(RestaurantLocation::new("The Great Steak", [-0.8, 0.0])); -/// restaurants.insert(RestaurantLocation::new("Fishy Fortune", [0.2, -0.2])); -/// -/// let my_location = [0.0, 0.0]; -/// -/// // Now find the closest restaurant! -/// let place = restaurants.nearest_neighbor(&my_location).unwrap(); -/// println!("Let's go to {}", place.data); -/// println!("It's really close, only {} miles", place.distance_2(&my_location)) -/// ``` -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct PointWithData { - /// Any data associated with a point. - pub data: T, - point: P, // Private to prevent modification. -} - -impl PointWithData { - /// Creates a new `PointWithData` with the provided data. - #[deprecated(note = "`PointWithData` is deprecated. Please switch to `GeomWithData`")] - pub fn new(data: T, point: P) -> Self { - PointWithData { data, point } - } - - /// Returns this point's position. - pub fn position(&self) -> &P { - &self.point - } -} - -impl RTreeObject for PointWithData -where - P: Point, -{ - type Envelope = AABB

; - - fn envelope(&self) -> Self::Envelope { - self.point.envelope() - } -} - -impl PointDistance for PointWithData -where - P: Point, -{ - fn distance_2(&self, point: &P) ->

::Scalar { - self.point.distance_2(point) - } - - fn contains_point(&self, point: &P) -> bool { - self.point.contains_point(point) - } -} diff --git a/thirdparty/rstar/src/primitives/rectangle.rs b/thirdparty/rstar/src/primitives/rectangle.rs deleted file mode 100644 index 6e1d0ba..0000000 --- a/thirdparty/rstar/src/primitives/rectangle.rs +++ /dev/null @@ -1,134 +0,0 @@ -use crate::aabb::AABB; -use crate::envelope::Envelope; -use crate::object::{PointDistance, RTreeObject}; -use crate::point::{Point, PointExt}; - -/// An n-dimensional rectangle defined by its two corners. -/// -/// This rectangle can be directly inserted into an r-tree. -/// -/// *Note*: Despite being called rectangle, this struct can be used -/// with more than two dimensions by using an appropriate point type. -/// -/// # Type parameters -/// `P`: The rectangle's [Point] type. -#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Rectangle

-where - P: Point, -{ - aabb: AABB

, -} - -impl

Rectangle

-where - P: Point, -{ - /// Creates a new rectangle defined by two corners. - pub fn from_corners(corner_1: P, corner_2: P) -> Self { - AABB::from_corners(corner_1, corner_2).into() - } - - /// Creates a new rectangle defined by it's [axis aligned bounding box(AABB). - pub fn from_aabb(aabb: AABB

) -> Self { - Rectangle { aabb } - } - - /// Returns the rectangle's lower corner. - /// - /// This is the point contained within the rectangle with the smallest coordinate value in each - /// dimension. - pub fn lower(&self) -> P { - self.aabb.lower() - } - - /// Returns the rectangle's upper corner. - /// - /// This is the point contained within the AABB with the largest coordinate value in each - /// dimension. - pub fn upper(&self) -> P { - self.aabb.upper() - } -} - -impl

From> for Rectangle

-where - P: Point, -{ - fn from(aabb: AABB

) -> Self { - Self::from_aabb(aabb) - } -} - -impl

RTreeObject for Rectangle

-where - P: Point, -{ - type Envelope = AABB

; - - fn envelope(&self) -> Self::Envelope { - self.aabb.clone() - } -} - -impl

Rectangle

-where - P: Point, -{ - /// Returns the nearest point within this rectangle to a given point. - /// - /// If `query_point` is contained within this rectangle, `query_point` is returned. - pub fn nearest_point(&self, query_point: &P) -> P { - self.aabb.min_point(query_point) - } -} - -impl

PointDistance for Rectangle

-where - P: Point, -{ - fn distance_2( - &self, - point: &::Point, - ) -> <::Point as Point>::Scalar { - self.nearest_point(point).sub(point).length_2() - } - - fn contains_point(&self, point: &::Point) -> bool { - self.aabb.contains_point(point) - } - - fn distance_2_if_less_or_equal( - &self, - point: &::Point, - max_distance_2: <::Point as Point>::Scalar, - ) -> Option<<::Point as Point>::Scalar> { - let distance_2 = self.distance_2(point); - if distance_2 <= max_distance_2 { - Some(distance_2) - } else { - None - } - } -} - -#[cfg(test)] -mod test { - use super::Rectangle; - use crate::object::PointDistance; - use approx::*; - - #[test] - fn rectangle_distance() { - let rectangle = Rectangle::from_corners([0.5, 0.5], [1.0, 2.0]); - - assert_abs_diff_eq!(rectangle.distance_2(&[0.5, 0.5]), 0.0); - assert_abs_diff_eq!(rectangle.distance_2(&[0.0, 0.5]), 0.5 * 0.5); - assert_abs_diff_eq!(rectangle.distance_2(&[0.5, 1.0]), 0.0); - assert_abs_diff_eq!(rectangle.distance_2(&[0.0, 0.0]), 0.5); - assert_abs_diff_eq!(rectangle.distance_2(&[0.0, 1.0]), 0.5 * 0.5); - assert_abs_diff_eq!(rectangle.distance_2(&[1.0, 3.0]), 1.0); - assert_abs_diff_eq!(rectangle.distance_2(&[1.0, 1.0]), 0.0); - } -} diff --git a/thirdparty/rstar/src/rtree.rs b/thirdparty/rstar/src/rtree.rs deleted file mode 100644 index 862afa9..0000000 --- a/thirdparty/rstar/src/rtree.rs +++ /dev/null @@ -1,1167 +0,0 @@ -use crate::algorithm::bulk_load; -use crate::algorithm::iterators::*; -use crate::algorithm::nearest_neighbor; -use crate::algorithm::nearest_neighbor::NearestNeighborDistance2Iterator; -use crate::algorithm::nearest_neighbor::NearestNeighborIterator; -use crate::algorithm::removal; -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::Point; -use core::ops::ControlFlow; - -#[cfg(not(test))] -use alloc::vec::Vec; - -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; - -impl Default for RTree -where - T: RTreeObject, - Params: RTreeParams, -{ - fn default() -> Self { - Self::new_with_params() - } -} - -/// An n-dimensional r-tree data structure. -/// -/// # R-Trees -/// R-Trees are data structures containing multi-dimensional objects like points, rectangles -/// or polygons. They are optimized for retrieving the nearest neighbor at any point. -/// -/// R-trees can efficiently find answers to queries like "Find the nearest point of a polygon", -/// "Find all police stations within a rectangle" or "Find the 10 nearest restaurants, sorted -/// by their distances". Compared to a naive implementation for these scenarios that runs -/// in `O(n)` for `n` inserted elements, r-trees reduce this time to `O(log(n))`. -/// -/// However, creating an r-tree is time consuming -/// and runs in `O(n * log(n))`. Thus, r-trees are suited best if many queries and only few -/// insertions are made. `rstar` also supports [bulk loading](RTree::bulk_load), -/// which cuts down the constant factors when creating an r-tree significantly compared to -/// sequential insertions. -/// -/// R-trees are also _dynamic_: points can be inserted and removed from an existing tree. -/// -/// ## Partitioning heuristics -/// The inserted objects are internally partitioned into several boxes which should have small -/// overlap and volume. This is done heuristically. While the originally proposed heuristic focused -/// on fast insertion operations, the resulting r-trees were often suboptimally structured. Another -/// heuristic, called `R*-tree` (r-star-tree), was proposed to improve the tree structure at the cost of -/// longer insertion operations and is currently the crate's only implemented -/// [InsertionStrategy]. -/// -/// # Usage -/// The items inserted into an r-tree must implement the [RTreeObject] -/// trait. To support nearest neighbor queries, implement the [PointDistance] -/// trait. Some useful geometric primitives that implement the above traits can be found in the -/// [crate::primitives] module. Several primitives in the [`geo-types`](https://docs.rs/geo-types/) crate also -/// implement these traits. -/// -/// ## Example -/// ``` -/// use rstar::RTree; -/// -/// let mut tree = RTree::new(); -/// tree.insert([0.1, 0.0f32]); -/// tree.insert([0.2, 0.1]); -/// tree.insert([0.3, 0.0]); -/// -/// assert_eq!(tree.nearest_neighbor(&[0.4, -0.1]), Some(&[0.3, 0.0])); -/// tree.remove(&[0.3, 0.0]); -/// assert_eq!(tree.nearest_neighbor(&[0.4, 0.3]), Some(&[0.2, 0.1])); -/// -/// assert_eq!(tree.size(), 2); -/// // &RTree implements IntoIterator! -/// for point in &tree { -/// println!("Tree contains a point {:?}", point); -/// } -/// ``` -/// -/// ## Supported point types -/// All types implementing the [Point] trait can be used as underlying point type. -/// By default, fixed size arrays can be used as points. -/// -/// # Associating Data with Geometries -/// Users wishing to store associated data with geometries can use [crate::primitives::GeomWithData]. -/// -/// # Runtime and Performance -/// The runtime of query operations (e.g. `nearest neighbor` or `contains`) is usually -/// `O(log(n))`, where `n` refers to the number of elements contained in the r-tree. -/// A naive sequential algorithm would take `O(n)` time. However, r-trees incur higher -/// build up times: inserting an element into an r-tree costs `O(log(n))` time. -/// -/// Most of the selection methods, meaning those with names beginning with `locate_`, -/// return iterators which are driven externally and can therefore be combined into -/// more complex pipelines using the combinators defined on the [`Iterator`] trait. -/// -/// This flexiblity does come at the cost of temporary heap allocations required -/// to keep track of the iteration state. Alternative methods using internal iteration -/// are provided to avoid this overhead, their names ending in `_int` or `_int_mut`. -/// -/// They use a callback-based interface to pass the selected objects on to the caller -/// thereby being able to use the stack to keep track of the state required for -/// traversing the tree. -/// -/// # Bulk loading -/// In many scenarios, insertion is only carried out once for many points. In this case, -/// [RTree::bulk_load] will be considerably faster. Its total run time -/// is still `O(nlog(n))`, i.e. `O(log(n))` per element inserted, but the scaling -/// factor is, on average, significantly improved compared with performing single -/// insertion n times in a row. **Note the performance caveat -/// related to the computation of the envelope**. -/// -/// # Element distribution -/// The tree's performance heavily relies on the spatial distribution of its elements. -/// Best performance is achieved if: -/// * No element is inserted more than once -/// * The overlapping area of elements is as small as -/// possible. -/// -/// For the edge case that all elements are overlapping (e.g, one and the same element -/// is contained `n` times), the performance of most operations usually degrades to `O(n)`. -/// -/// # Type Parameters -/// * `T`: The type of objects stored in the r-tree. -/// * `Params`: Compile time parameters that change the r-tree's internal layout. Refer to the -/// [RTreeParams] trait for more information. -/// -/// # Defining methods generic over r-trees -/// 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) -/// where -/// T: RTreeObject, -/// Params: RTreeParams -/// { -/// // ... -/// } -/// ``` -/// Otherwise, any user of `generic_rtree_function` would be forced to use -/// a tree with default parameters. -/// -/// # (De)Serialization -/// Enable the `serde` feature for [Serde](https://crates.io/crates/serde) support. -/// -/// ## Further reading -/// For more information refer to the [wikipedia article](https://en.wikipedia.org/wiki/R-tree). -/// -#[derive(Clone)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr( - feature = "serde", - serde(bound( - serialize = "T: Serialize, T::Envelope: Serialize", - deserialize = "T: Deserialize<'de>, T::Envelope: Deserialize<'de>" - )) -)] -pub struct RTree -where - Params: RTreeParams, - T: RTreeObject, -{ - root: ParentNode, - size: usize, - _params: ::core::marker::PhantomData, -} - -struct DebugHelper<'a, T, Params> -where - T: RTreeObject + ::core::fmt::Debug + 'a, - Params: RTreeParams + 'a, -{ - rtree: &'a RTree, -} - -impl<'a, T, Params> ::core::fmt::Debug for DebugHelper<'a, T, Params> -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 -where - Params: RTreeParams, - T: RTreeObject + ::core::fmt::Debug, -{ - fn fmt(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - formatter - .debug_struct("RTree") - .field("size", &self.size) - .field("items", &DebugHelper { rtree: self }) - .finish() - } -} - -impl RTree -where - T: RTreeObject, -{ - /// Creates a new, empty r-tree. - /// - /// The created r-tree is configured with [default parameters](DefaultParams). - pub fn new() -> Self { - Self::new_with_params() - } - - /// Creates a new r-tree with some elements already inserted. - /// - /// This method should be the preferred way for creating r-trees. It both - /// runs faster and yields an r-tree with better internal structure that - /// improves query performance. - /// - /// This method implements the overlap minimizing top-down bulk loading algorithm (OMT) - /// as described in [this paper by Lee and Lee (2003)](http://ceur-ws.org/Vol-74/files/FORUM_18.pdf). - /// - /// # Runtime - /// Bulk loading runs in `O(n * log(n))`, where `n` is the number of loaded - /// elements. - /// - /// # Note - /// The envelope of each element will be accessed many times during loading. If that computation - /// is expensive, **consider memoizing it** using [`CachedEnvelope`][crate::primitives::CachedEnvelope]. - pub fn bulk_load(elements: Vec) -> Self { - Self::bulk_load_with_params(elements) - } -} - -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::(); - RTree { - root: ParentNode::new_root::(), - size: 0, - _params: Default::default(), - } - } - - /// Creates a new r-tree with some given elements and configurable parameters. - /// - /// 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>) - } - - /// Returns the number of objects in an r-tree. - /// - /// # Example - /// ``` - /// use rstar::RTree; - /// - /// let mut tree = RTree::new(); - /// assert_eq!(tree.size(), 0); - /// tree.insert([0.0, 1.0, 2.0]); - /// assert_eq!(tree.size(), 1); - /// tree.remove(&[0.0, 1.0, 2.0]); - /// assert_eq!(tree.size(), 0); - /// ``` - pub fn size(&self) -> usize { - self.size - } - - pub(crate) fn size_mut(&mut self) -> &mut usize { - &mut self.size - } - - /// Returns an iterator over all elements contained in the tree. - /// - /// The order in which the elements are returned is not specified. - /// - /// # Example - /// ``` - /// use rstar::RTree; - /// let tree = RTree::bulk_load(vec![(0.0, 0.1), (0.3, 0.2), (0.4, 0.2)]); - /// for point in tree.iter() { - /// println!("This tree contains point {:?}", point); - /// } - /// ``` - pub fn iter(&self) -> RTreeIterator { - RTreeIterator::new(&self.root, SelectAllFunc) - } - - /// Returns an iterator over all mutable elements contained in the tree. - /// - /// The order in which the elements are returned is not specified. - /// - /// *Note*: It is a logic error to change an inserted item's position or dimensions. This - /// method is primarily meant for own implementations of [RTreeObject] - /// which can contain arbitrary additional data. - /// If the position or location of an inserted object need to change, you will need to [RTree::remove] - /// and reinsert it. - /// - pub fn iter_mut(&mut self) -> RTreeIteratorMut { - RTreeIteratorMut::new(&mut self.root, SelectAllFunc) - } - - /// Returns all elements contained in an [Envelope]. - /// - /// Usually, an envelope is an [axis aligned bounding box](crate::AABB). This - /// method can be used to retrieve all elements that are fully contained within an envelope. - /// - /// # Example - /// ``` - /// use rstar::{RTree, AABB}; - /// let mut tree = RTree::bulk_load(vec![ - /// [0.0, 0.0], - /// [0.0, 1.0], - /// [1.0, 1.0] - /// ]); - /// let half_unit_square = AABB::from_corners([0.0, 0.0], [0.5, 1.0]); - /// let unit_square = AABB::from_corners([0.0, 0.0], [1.0, 1.0]); - /// let elements_in_half_unit_square = tree.locate_in_envelope(&half_unit_square); - /// let elements_in_unit_square = tree.locate_in_envelope(&unit_square); - /// assert_eq!(elements_in_half_unit_square.count(), 2); - /// assert_eq!(elements_in_unit_square.count(), 3); - /// ``` - pub fn locate_in_envelope(&self, envelope: &T::Envelope) -> LocateInEnvelope { - LocateInEnvelope::new(&self.root, SelectInEnvelopeFunction::new(envelope.clone())) - } - - /// Mutable variant of [locate_in_envelope](#method.locate_in_envelope). - pub fn locate_in_envelope_mut(&mut self, envelope: &T::Envelope) -> LocateInEnvelopeMut { - LocateInEnvelopeMut::new( - &mut self.root, - SelectInEnvelopeFunction::new(envelope.clone()), - ) - } - - /// Variant of [`locate_in_envelope`][Self::locate_in_envelope] using internal iteration. - pub fn locate_in_envelope_int<'a, V, B>( - &'a self, - envelope: &T::Envelope, - mut visitor: V, - ) -> ControlFlow - where - V: FnMut(&'a T) -> ControlFlow, - { - select_nodes( - self.root(), - &SelectInEnvelopeFunction::new(envelope.clone()), - &mut visitor, - ) - } - - /// Mutable variant of [`locate_in_envelope_mut`][Self::locate_in_envelope_mut]. - pub fn locate_in_envelope_int_mut<'a, V, B>( - &'a mut self, - envelope: &T::Envelope, - mut visitor: V, - ) -> ControlFlow - where - V: FnMut(&'a mut T) -> ControlFlow, - { - select_nodes_mut( - self.root_mut(), - &SelectInEnvelopeFunction::new(envelope.clone()), - &mut visitor, - ) - } - - /// Returns a draining iterator over all elements contained in the tree. - /// - /// The order in which the elements are returned is not specified. - /// - /// See - /// [drain_with_selection_function](#method.drain_with_selection_function) - /// for more information. - pub fn drain(&mut self) -> DrainIterator { - self.drain_with_selection_function(SelectAllFunc) - } - - /// Draining variant of [locate_in_envelope](#method.locate_in_envelope). - pub fn drain_in_envelope( - &mut self, - envelope: T::Envelope, - ) -> DrainIterator, Params> { - let sel = SelectInEnvelopeFunction::new(envelope); - self.drain_with_selection_function(sel) - } - - /// Returns all elements whose envelope intersects a given envelope. - /// - /// Any element fully contained within an envelope is also returned by this method. Two - /// envelopes that "touch" each other (e.g. by sharing only a common corner) are also - /// considered to intersect. Usually, an envelope is an [axis aligned bounding box](crate::AABB). - /// This method will return all elements whose AABB has some common area with - /// a given AABB. - /// - /// # Example - /// ``` - /// use rstar::{RTree, AABB}; - /// use rstar::primitives::Rectangle; - /// - /// let left_piece = AABB::from_corners([0.0, 0.0], [0.4, 1.0]); - /// let right_piece = AABB::from_corners([0.6, 0.0], [1.0, 1.0]); - /// let middle_piece = AABB::from_corners([0.25, 0.0], [0.75, 1.0]); - /// - /// let mut tree = RTree::>::bulk_load(vec![ - /// left_piece.into(), - /// right_piece.into(), - /// middle_piece.into(), - /// ]); - /// - /// let elements_intersecting_left_piece = tree.locate_in_envelope_intersecting(&left_piece); - /// // The left piece should not intersect the right piece! - /// assert_eq!(elements_intersecting_left_piece.count(), 2); - /// let elements_intersecting_middle = tree.locate_in_envelope_intersecting(&middle_piece); - /// // Only the middle piece intersects all pieces within the tree - /// assert_eq!(elements_intersecting_middle.count(), 3); - /// - /// let large_piece = AABB::from_corners([-100., -100.], [100., 100.]); - /// let elements_intersecting_large_piece = tree.locate_in_envelope_intersecting(&large_piece); - /// // Any element that is fully contained should also be returned: - /// assert_eq!(elements_intersecting_large_piece.count(), 3); - /// ``` - pub fn locate_in_envelope_intersecting( - &self, - envelope: &T::Envelope, - ) -> LocateInEnvelopeIntersecting { - LocateInEnvelopeIntersecting::new( - &self.root, - SelectInEnvelopeFuncIntersecting::new(envelope.clone()), - ) - } - - /// Mutable variant of [locate_in_envelope_intersecting](#method.locate_in_envelope_intersecting) - pub fn locate_in_envelope_intersecting_mut( - &mut self, - envelope: &T::Envelope, - ) -> LocateInEnvelopeIntersectingMut { - LocateInEnvelopeIntersectingMut::new( - &mut self.root, - SelectInEnvelopeFuncIntersecting::new(envelope.clone()), - ) - } - - /// Variant of [`locate_in_envelope_intersecting`][Self::locate_in_envelope_intersecting] using internal iteration. - pub fn locate_in_envelope_intersecting_int<'a, V, B>( - &'a self, - envelope: &T::Envelope, - mut visitor: V, - ) -> ControlFlow - where - V: FnMut(&'a T) -> ControlFlow, - { - select_nodes( - self.root(), - &SelectInEnvelopeFuncIntersecting::new(envelope.clone()), - &mut visitor, - ) - } - - /// Mutable variant of [`locate_in_envelope_intersecting_int`][Self::locate_in_envelope_intersecting_int]. - pub fn locate_in_envelope_intersecting_int_mut<'a, V, B>( - &'a mut self, - envelope: &T::Envelope, - mut visitor: V, - ) -> ControlFlow - where - V: FnMut(&'a mut T) -> ControlFlow, - { - select_nodes_mut( - self.root_mut(), - &SelectInEnvelopeFuncIntersecting::new(envelope.clone()), - &mut visitor, - ) - } - - /// Locates elements in the r-tree defined by a selection function. - /// - /// Refer to the documentation of [`SelectionFunction`] for - /// more information. - /// - /// Usually, other `locate` methods should cover most common use cases. This method is only required - /// in more specific situations. - pub fn locate_with_selection_function>( - &self, - selection_function: S, - ) -> SelectionIterator { - SelectionIterator::new(&self.root, selection_function) - } - - /// Mutable variant of [`locate_with_selection_function`](#method.locate_with_selection_function). - pub fn locate_with_selection_function_mut>( - &mut self, - selection_function: S, - ) -> SelectionIteratorMut { - SelectionIteratorMut::new(&mut self.root, selection_function) - } - - /// Returns all possible intersecting objects of this and another tree. - /// - /// This will return all objects whose _envelopes_ intersect. No geometric intersection - /// checking is performed. - pub fn intersection_candidates_with_other_tree<'a, U>( - &'a self, - other: &'a RTree, - ) -> IntersectionIterator<'a, T, U> - where - U: RTreeObject, - { - IntersectionIterator::new(self.root(), other.root()) - } - - /// Returns the tree's root node. - /// - /// Usually, you will not need to call this method. However, for debugging purposes or for - /// advanced algorithms, knowledge about the tree's internal structure may be required. - /// For these cases, this method serves as an entry point. - pub fn root(&self) -> &ParentNode { - &self.root - } - - pub(crate) fn root_mut(&mut self) -> &mut ParentNode { - &mut self.root - } - - fn new_from_bulk_loading( - elements: Vec, - root_loader: impl Fn(Vec) -> ParentNode, - ) -> Self { - verify_parameters::(); - let size = elements.len(); - let root = if size == 0 { - ParentNode::new_root::() - } else { - root_loader(elements) - }; - RTree { - root, - size, - _params: Default::default(), - } - } - - /// Removes and returns a single element from the tree. The element to remove is specified - /// by a [`SelectionFunction`]. - /// - /// See also: [`RTree::remove`], [`RTree::remove_at_point`] - /// - pub fn remove_with_selection_function(&mut self, function: F) -> Option - where - F: SelectionFunction, - { - removal::DrainIterator::new(self, function).take(1).last() - } - - /// Drain elements selected by a [`SelectionFunction`]. Returns an - /// iterator that successively removes selected elements and returns - /// them. This is the most generic drain API, see also: - /// [`RTree::drain_in_envelope_intersecting`], - /// [`RTree::drain_within_distance`]. - /// - /// # Remarks - /// - /// This API is similar to `Vec::drain_filter`, but stopping the - /// 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 - where - F: SelectionFunction, - { - removal::DrainIterator::new(self, function) - } - - /// Drains elements intersecting the `envelope`. Similar to - /// `locate_in_envelope_intersecting`, except the elements are removed - /// and returned via an iterator. - pub fn drain_in_envelope_intersecting( - &mut self, - envelope: T::Envelope, - ) -> DrainIterator, Params> { - let selection_function = SelectInEnvelopeFuncIntersecting::new(envelope); - self.drain_with_selection_function(selection_function) - } -} - -impl RTree -where - Params: RTreeParams, - T: PointDistance, -{ - /// Returns a single object that covers a given point. - /// - /// Method [contains_point](PointDistance::contains_point) - /// is used to determine if a tree element contains the given point. - /// - /// If multiple elements contain the given point, any of them is returned. - pub fn locate_at_point(&self, point: &::Point) -> Option<&T> { - self.locate_all_at_point(point).next() - } - - /// Mutable variant of [RTree::locate_at_point]. - pub fn locate_at_point_mut( - &mut self, - point: &::Point, - ) -> Option<&mut T> { - self.locate_all_at_point_mut(point).next() - } - - /// Variant of [`locate_at_point`][Self::locate_at_point] using internal iteration. - pub fn locate_at_point_int(&self, point: &::Point) -> Option<&T> { - match self.locate_all_at_point_int(point, ControlFlow::Break) { - ControlFlow::Break(node) => Some(node), - ControlFlow::Continue(()) => None, - } - } - - /// Mutable variant of [`locate_at_point_int`][Self::locate_at_point_int]. - pub fn locate_at_point_int_mut( - &mut self, - point: &::Point, - ) -> Option<&mut T> { - match self.locate_all_at_point_int_mut(point, ControlFlow::Break) { - ControlFlow::Break(node) => Some(node), - ControlFlow::Continue(()) => None, - } - } - - /// Locate all elements containing a given point. - /// - /// Method [PointDistance::contains_point] is used - /// to determine if a tree element contains the given point. - /// # Example - /// ``` - /// use rstar::RTree; - /// use rstar::primitives::Rectangle; - /// - /// let tree = RTree::bulk_load(vec![ - /// Rectangle::from_corners([0.0, 0.0], [2.0, 2.0]), - /// Rectangle::from_corners([1.0, 1.0], [3.0, 3.0]) - /// ]); - /// - /// assert_eq!(tree.locate_all_at_point(&[1.5, 1.5]).count(), 2); - /// assert_eq!(tree.locate_all_at_point(&[0.0, 0.0]).count(), 1); - /// assert_eq!(tree.locate_all_at_point(&[-1., 0.0]).count(), 0); - /// ``` - pub fn locate_all_at_point( - &self, - point: &::Point, - ) -> LocateAllAtPoint { - LocateAllAtPoint::new(&self.root, SelectAtPointFunction::new(point.clone())) - } - - /// Mutable variant of [`locate_all_at_point`][Self::locate_all_at_point]. - pub fn locate_all_at_point_mut( - &mut self, - point: &::Point, - ) -> LocateAllAtPointMut { - LocateAllAtPointMut::new(&mut self.root, SelectAtPointFunction::new(point.clone())) - } - - /// Variant of [`locate_all_at_point`][Self::locate_all_at_point] using internal iteration. - pub fn locate_all_at_point_int<'a, V, B>( - &'a self, - point: &::Point, - mut visitor: V, - ) -> ControlFlow - where - V: FnMut(&'a T) -> ControlFlow, - { - select_nodes( - &self.root, - &SelectAtPointFunction::new(point.clone()), - &mut visitor, - ) - } - - /// Mutable variant of [`locate_all_at_point_int`][Self::locate_all_at_point_int]. - pub fn locate_all_at_point_int_mut<'a, V, B>( - &'a mut self, - point: &::Point, - mut visitor: V, - ) -> ControlFlow - where - V: FnMut(&'a mut T) -> ControlFlow, - { - select_nodes_mut( - &mut self.root, - &SelectAtPointFunction::new(point.clone()), - &mut visitor, - ) - } - - /// Removes an element containing a given point. - /// - /// The removed element, if any, is returned. If multiple elements cover the given point, - /// only one of them is removed and returned. - /// - /// # Example - /// ``` - /// use rstar::RTree; - /// use rstar::primitives::Rectangle; - /// - /// let mut tree = RTree::bulk_load(vec![ - /// Rectangle::from_corners([0.0, 0.0], [2.0, 2.0]), - /// Rectangle::from_corners([1.0, 1.0], [3.0, 3.0]) - /// ]); - /// - /// assert!(tree.remove_at_point(&[1.5, 1.5]).is_some()); - /// assert!(tree.remove_at_point(&[1.5, 1.5]).is_some()); - /// assert!(tree.remove_at_point(&[1.5, 1.5]).is_none()); - ///``` - pub fn remove_at_point(&mut self, point: &::Point) -> Option { - let removal_function = SelectAtPointFunction::new(point.clone()); - self.remove_with_selection_function(removal_function) - } -} - -impl RTree -where - Params: RTreeParams, - T: RTreeObject + PartialEq, -{ - /// Returns `true` if a given element is equal (`==`) to an element in the - /// r-tree. - /// - /// This method will only work correctly if two equal elements also have the - /// same envelope. - /// - /// # Example - /// ``` - /// use rstar::RTree; - /// - /// let mut tree = RTree::new(); - /// assert!(!tree.contains(&[0.0, 2.0])); - /// tree.insert([0.0, 2.0]); - /// assert!(tree.contains(&[0.0, 2.0])); - /// ``` - pub fn contains(&self, t: &T) -> bool { - self.locate_in_envelope(&t.envelope()).any(|e| e == t) - } - - /// Removes and returns an element of the r-tree equal (`==`) to a given element. - /// - /// If multiple elements equal to the given elements are contained in the tree, only - /// one of them is removed and returned. - /// - /// This method will only work correctly if two equal elements also have the - /// same envelope. - /// - /// # Example - /// ``` - /// use rstar::RTree; - /// - /// let mut tree = RTree::new(); - /// tree.insert([0.0, 2.0]); - /// // The element can be inserted twice just fine - /// tree.insert([0.0, 2.0]); - /// assert!(tree.remove(&[0.0, 2.0]).is_some()); - /// assert!(tree.remove(&[0.0, 2.0]).is_some()); - /// assert!(tree.remove(&[0.0, 2.0]).is_none()); - /// ``` - pub fn remove(&mut self, t: &T) -> Option { - let removal_function = SelectEqualsFunction::new(t); - self.remove_with_selection_function(removal_function) - } -} - -impl RTree -where - Params: RTreeParams, - T: PointDistance, -{ - /// Returns the nearest neighbor for a given point. - /// - /// The distance is calculated by calling - /// [PointDistance::distance_2] - /// - /// # Example - /// ``` - /// use rstar::RTree; - /// let tree = RTree::bulk_load(vec![ - /// [0.0, 0.0], - /// [0.0, 1.0], - /// ]); - /// assert_eq!(tree.nearest_neighbor(&[-1., 0.0]), Some(&[0.0, 0.0])); - /// assert_eq!(tree.nearest_neighbor(&[0.0, 2.0]), Some(&[0.0, 1.0])); - /// ``` - pub fn nearest_neighbor(&self, query_point: &::Point) -> Option<&T> { - if self.size > 0 { - // The single-nearest-neighbor retrieval may in rare cases return None due to - // rounding issues. The iterator will still work, though. - nearest_neighbor::nearest_neighbor(&self.root, query_point.clone()) - .or_else(|| self.nearest_neighbor_iter(query_point).next()) - } else { - None - } - } - - /// Returns the nearest neighbors for a given point. - /// - /// The distance is calculated by calling - /// [PointDistance::distance_2] - /// - /// All returned values will have the exact same distance from the given query point. - /// Returns an empty `Vec` if the tree is empty. - /// - /// # Example - /// ``` - /// use rstar::RTree; - /// let tree = RTree::bulk_load(vec![ - /// [0.0, 0.0], - /// [0.0, 1.0], - /// [1.0, 0.0], - /// ]); - /// - /// // A single nearest neighbor - /// assert_eq!(tree.nearest_neighbors(&[0.01, 0.01]), &[&[0.0, 0.0]]); - /// - /// // Two nearest neighbors - /// let nearest_two = tree.nearest_neighbors(&[1.0, 1.0]); - /// assert_eq!(nearest_two.len(), 2); - /// assert!(nearest_two.contains(&&[0.0, 1.0])); - /// assert!(nearest_two.contains(&&[1.0, 0.0])); - /// ``` - pub fn nearest_neighbors(&self, query_point: &::Point) -> Vec<&T> { - nearest_neighbor::nearest_neighbors(&self.root, query_point.clone()) - } - - /// Returns all elements of the tree within a certain distance. - /// - /// The elements may be returned in any order. Each returned element - /// will have a squared distance less or equal to the given squared distance. - /// - /// This method makes use of [PointDistance::distance_2_if_less_or_equal]. - /// If performance is critical and the distance calculation to the object is fast, - /// overwriting this function may be beneficial. - pub fn locate_within_distance( - &self, - query_point: ::Point, - max_squared_radius: <::Point as Point>::Scalar, - ) -> LocateWithinDistanceIterator { - let selection_function = SelectWithinDistanceFunction::new(query_point, max_squared_radius); - LocateWithinDistanceIterator::new(self.root(), selection_function) - } - - /// Drain all elements of the tree within a certain distance. - /// - /// Similar to [`RTree::locate_within_distance`], but removes and - /// returns the elements via an iterator. - pub fn drain_within_distance( - &mut self, - query_point: ::Point, - max_squared_radius: <::Point as Point>::Scalar, - ) -> DrainIterator, Params> { - let selection_function = SelectWithinDistanceFunction::new(query_point, max_squared_radius); - self.drain_with_selection_function(selection_function) - } - - /// Returns all elements of the tree sorted by their distance to a given point. - /// - /// # Runtime - /// Every `next()` call runs in `O(log(n))`. Creating the iterator runs in - /// `O(log(n))`. - /// The [r-tree documentation](RTree) contains more information about - /// r-tree performance. - /// - /// # Example - /// ``` - /// use rstar::RTree; - /// let tree = RTree::bulk_load(vec![ - /// [0.0, 0.0], - /// [0.0, 1.0], - /// ]); - /// - /// let nearest_neighbors = tree.nearest_neighbor_iter(&[0.5, 0.0]).collect::>(); - /// assert_eq!(nearest_neighbors, vec![&[0.0, 0.0], &[0.0, 1.0]]); - /// ``` - pub fn nearest_neighbor_iter( - &self, - query_point: &::Point, - ) -> NearestNeighborIterator { - nearest_neighbor::NearestNeighborIterator::new(&self.root, query_point.clone()) - } - - /// Returns `(element, distance^2)` tuples of the tree sorted by their distance to a given point. - /// - /// The distance is calculated by calling - /// [PointDistance::distance_2]. - #[deprecated(note = "Please use nearest_neighbor_iter_with_distance_2 instead")] - pub fn nearest_neighbor_iter_with_distance( - &self, - query_point: &::Point, - ) -> NearestNeighborDistance2Iterator { - nearest_neighbor::NearestNeighborDistance2Iterator::new(&self.root, query_point.clone()) - } - - /// Returns `(element, distance^2)` tuples of the tree sorted by their distance to a given point. - /// - /// The distance is calculated by calling - /// [PointDistance::distance_2]. - pub fn nearest_neighbor_iter_with_distance_2( - &self, - query_point: &::Point, - ) -> NearestNeighborDistance2Iterator { - nearest_neighbor::NearestNeighborDistance2Iterator::new(&self.root, query_point.clone()) - } - - /// Removes the nearest neighbor for a given point and returns it. - /// - /// The distance is calculated by calling - /// [PointDistance::distance_2]. - /// - /// # Example - /// ``` - /// use rstar::RTree; - /// let mut tree = RTree::bulk_load(vec![ - /// [0.0, 0.0], - /// [0.0, 1.0], - /// ]); - /// assert_eq!(tree.pop_nearest_neighbor(&[0.0, 0.0]), Some([0.0, 0.0])); - /// assert_eq!(tree.pop_nearest_neighbor(&[0.0, 0.0]), Some([0.0, 1.0])); - /// assert_eq!(tree.pop_nearest_neighbor(&[0.0, 0.0]), None); - /// ``` - pub fn pop_nearest_neighbor( - &mut self, - query_point: &::Point, - ) -> Option { - if let Some(neighbor) = self.nearest_neighbor(query_point) { - let removal_function = SelectByAddressFunction::new(neighbor.envelope(), neighbor); - self.remove_with_selection_function(removal_function) - } else { - None - } - } -} - -impl RTree -where - T: RTreeObject, - Params: RTreeParams, -{ - /// Inserts a new element into the r-tree. - /// - /// If the element is already present in the tree, it will now be present twice. - /// - /// # Runtime - /// This method runs in `O(log(n))`. - /// The [r-tree documentation](RTree) contains more information about - /// r-tree performance. - pub fn insert(&mut self, t: T) { - Params::DefaultInsertionStrategy::insert(self, t); - self.size += 1; - } -} - -impl IntoIterator for RTree -where - T: RTreeObject, - Params: RTreeParams, -{ - type IntoIter = IntoIter; - type Item = T; - - fn into_iter(self) -> Self::IntoIter { - IntoIter::new(self.root) - } -} - -impl<'a, T, Params> IntoIterator for &'a RTree -where - T: RTreeObject, - Params: RTreeParams, -{ - type IntoIter = RTreeIterator<'a, T>; - type Item = &'a T; - - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -impl<'a, T, Params> IntoIterator for &'a mut RTree -where - T: RTreeObject, - Params: RTreeParams, -{ - type IntoIter = RTreeIteratorMut<'a, T>; - type Item = &'a mut T; - - fn into_iter(self) -> Self::IntoIter { - self.iter_mut() - } -} - -#[cfg(test)] -mod test { - use super::RTree; - use crate::algorithm::rstar::RStarInsertionStrategy; - use crate::params::RTreeParams; - 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 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); - 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(); - assert_eq!(tree.size(), 0); - } - - #[test] - fn test_insert_single() { - let mut tree: RTree<_> = RTree::new(); - tree.insert([0.02f32, 0.4f32]); - assert_eq!(tree.size(), 1); - assert!(tree.contains(&[0.02, 0.4])); - assert!(!tree.contains(&[0.3, 0.2])); - } - - #[test] - fn test_insert_many() { - const NUM_POINTS: usize = 1000; - let points = create_random_points(NUM_POINTS, SEED_1); - let mut tree = RTree::new(); - for p in &points { - tree.insert(*p); - tree.root.sanity_check::(true); - } - assert_eq!(tree.size(), NUM_POINTS); - for p in &points { - assert!(tree.contains(p)); - } - } - - #[test] - fn test_fmt_debug() { - let tree = RTree::bulk_load(vec![[0, 1], [0, 1]]); - let debug: String = format!("{:?}", tree); - assert_eq!(debug, "RTree { size: 2, items: {[0, 1], [0, 1]} }"); - } - - #[test] - fn test_default() { - let tree: RTree<[f32; 2]> = Default::default(); - assert_eq!(tree.size(), 0); - } - - #[cfg(feature = "serde")] - #[test] - fn test_serialization() { - use crate::test_utilities::create_random_integers; - - use serde_json; - const SIZE: usize = 20; - let points = create_random_integers::<[i32; 2]>(SIZE, SEED_1); - let tree = RTree::bulk_load(points.clone()); - let json = serde_json::to_string(&tree).expect("Serializing tree failed"); - let parsed: RTree<[i32; 2]> = - serde_json::from_str(&json).expect("Deserializing tree failed"); - assert_eq!(parsed.size(), SIZE); - for point in &points { - assert!(parsed.contains(point)); - } - } - - #[test] - fn test_bulk_load_crash() { - let bulk_nodes = vec![ - [570.0, 1080.0, 89.0], - [30.0, 1080.0, 627.0], - [1916.0, 1080.0, 68.0], - [274.0, 1080.0, 790.0], - [476.0, 1080.0, 895.0], - [1557.0, 1080.0, 250.0], - [1546.0, 1080.0, 883.0], - [1512.0, 1080.0, 610.0], - [1729.0, 1080.0, 358.0], - [1841.0, 1080.0, 434.0], - [1752.0, 1080.0, 696.0], - [1674.0, 1080.0, 705.0], - [136.0, 1080.0, 22.0], - [1593.0, 1080.0, 71.0], - [586.0, 1080.0, 272.0], - [348.0, 1080.0, 373.0], - [502.0, 1080.0, 2.0], - [1488.0, 1080.0, 1072.0], - [31.0, 1080.0, 526.0], - [1695.0, 1080.0, 559.0], - [1663.0, 1080.0, 298.0], - [316.0, 1080.0, 417.0], - [1348.0, 1080.0, 731.0], - [784.0, 1080.0, 126.0], - [225.0, 1080.0, 847.0], - [79.0, 1080.0, 819.0], - [320.0, 1080.0, 504.0], - [1714.0, 1080.0, 1026.0], - [264.0, 1080.0, 229.0], - [108.0, 1080.0, 158.0], - [1665.0, 1080.0, 604.0], - [496.0, 1080.0, 231.0], - [1813.0, 1080.0, 865.0], - [1200.0, 1080.0, 326.0], - [1661.0, 1080.0, 818.0], - [135.0, 1080.0, 229.0], - [424.0, 1080.0, 1016.0], - [1708.0, 1080.0, 791.0], - [1626.0, 1080.0, 682.0], - [442.0, 1080.0, 895.0], - ]; - - let nodes = vec![ - [1916.0, 1060.0, 68.0], - [1664.0, 1060.0, 298.0], - [1594.0, 1060.0, 71.0], - [225.0, 1060.0, 846.0], - [1841.0, 1060.0, 434.0], - [502.0, 1060.0, 2.0], - [1625.5852, 1060.0122, 682.0], - [1348.5273, 1060.0029, 731.08124], - [316.36127, 1060.0298, 418.24515], - [1729.3253, 1060.0023, 358.50134], - ]; - let mut tree = RTree::bulk_load(bulk_nodes); - for node in nodes { - // Bulk loading will create nodes larger than Params::MAX_SIZE, - // which is intentional and not harmful. - tree.insert(node); - tree.root().sanity_check::(false); - } - } -} diff --git a/thirdparty/rstar/src/test_utilities.rs b/thirdparty/rstar/src/test_utilities.rs deleted file mode 100644 index df5e4e9..0000000 --- a/thirdparty/rstar/src/test_utilities.rs +++ /dev/null @@ -1,51 +0,0 @@ -use crate::primitives::*; -use crate::{Point, RTreeObject}; -use rand::distributions::Uniform; -use rand::{Rng, SeedableRng}; -use rand_hc::Hc128Rng; - -pub type Seed = [u8; 32]; - -pub const SEED_1: &Seed = b"wPYxAkIiHcEmSBAxQFoXFrpYToCe1B71"; -pub const SEED_2: &Seed = b"4KbTVjPT4DXSwWAsQM5dkWWywPKZRfCX"; - -pub fn create_random_integers>(num_points: usize, seed: &Seed) -> Vec

{ - let mut result = Vec::with_capacity(num_points); - let mut rng = Hc128Rng::from_seed(*seed); - let range = Uniform::from(-100_000..100_000); - - for _ in 0..num_points { - let p = Point::generate(|_| rng.sample(range)); - result.push(p); - } - result -} - -pub fn create_random_points(num_points: usize, seed: &Seed) -> Vec<[f64; 2]> { - let mut result = Vec::with_capacity(num_points); - let mut rng = Hc128Rng::from_seed(*seed); - for _ in 0..num_points { - result.push(rng.gen()); - } - result -} - -pub fn create_random_lines(num_lines: usize, seed: &Seed) -> Vec> { - let mut result = Vec::with_capacity(num_lines); - let mut rng = Hc128Rng::from_seed(*seed); - let factor = 10. / num_lines as f64; - for _ in 0..num_lines { - let point: [f64; 2] = rng.gen(); - let offset: [f64; 2] = rng.gen(); - result.push(Line::new( - point, - [point[0] + offset[1] * factor, point[1] + offset[1] * factor], - )); - } - result -} - -pub fn create_random_rectangles(num_rectangles: usize, seed: &Seed) -> Vec> { - let lines = create_random_lines(num_rectangles, seed); - lines.iter().map(|line| line.envelope().into()).collect() -} From ffcc1154113d66286a2c99a80bb89e7f39bad412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Mockers?= Date: Fri, 27 Mar 2026 23:31:20 +0100 Subject: [PATCH 5/7] use internal iteration to avoid an allocation --- src/layers.rs | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/layers.rs b/src/layers.rs index 01702bb..9958621 100644 --- a/src/layers.rs +++ b/src/layers.rs @@ -187,6 +187,27 @@ impl Layer { }) } + /// Find the first polygon containing the point using internal iteration (no SmallVec allocation). + #[cfg_attr(feature = "tracing", instrument(skip_all))] + #[inline(always)] + pub(crate) fn find_first_point_location_baked(&self, point: &Vec2) -> Option { + use core::ops::ControlFlow; + let query_point = [point.x, point.y]; + let mut result = None; + self.baked_polygons + .as_ref() + .unwrap() + .locate_in_envelope_intersecting_int(rstar::AABB::from_point(query_point), |bp| { + if self.point_in_polygon(*point, &self.polygons[bp.index]) { + result = Some(bp.index as u32); + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + }); + result + } + #[cfg_attr(feature = "tracing", instrument(skip_all))] #[inline(always)] fn point_in_polygon(&self, point: Vec2, polygon: &Polygon) -> bool { @@ -238,7 +259,7 @@ impl Layer { if self.baked_polygons.is_none() { self.get_point_locations_unit(point).next() } else { - self.get_point_locations_unit_baked(&point).next() + self.find_first_point_location_baked(&point) } .unwrap_or(u32::MAX) }) @@ -312,7 +333,7 @@ impl Layer { let poly = if self.baked_polygons.is_none() { self.get_point_locations_unit(new_point).next() } else { - self.get_point_locations_unit_baked(&new_point).next() + self.find_first_point_location_baked(&new_point) } .unwrap_or(u32::MAX); @@ -384,7 +405,7 @@ impl Layer { let poly = if self.baked_polygons.is_none() { self.get_point_locations_unit(point).next() } else { - self.get_point_locations_unit_baked(&point).next() + self.find_first_point_location_baked(&point) } .unwrap_or(u32::MAX); if poly != u32::MAX { From d97b1442eff93abd9ac184cd0b82a517762778ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Mockers?= Date: Fri, 27 Mar 2026 23:32:29 +0100 Subject: [PATCH 6/7] unused --- src/layers.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/layers.rs b/src/layers.rs index 9958621..b3792a1 100644 --- a/src/layers.rs +++ b/src/layers.rs @@ -194,7 +194,8 @@ impl Layer { use core::ops::ControlFlow; let query_point = [point.x, point.y]; let mut result = None; - self.baked_polygons + let _ = self + .baked_polygons .as_ref() .unwrap() .locate_in_envelope_intersecting_int(rstar::AABB::from_point(query_point), |bp| { From 9baa48ee52b3cc76abd8bc2a66a1077acecb0051 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Mockers?= Date: Fri, 27 Mar 2026 23:32:38 +0100 Subject: [PATCH 7/7] merged rstar --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e191f1e..b948780 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ tracing = { version = "0.1", optional = true } hashbrown = { version = "0.16" } glam = { version = "0.30.8", features = ["approx"] } smallvec = { version = "1.15", features = ["union", "const_generics"] } -rstar = { version = "0.12", git = "https://github.com/mockersf/rstar", branch = "AABB-from-known-bounds" } +rstar = { version = "0.12", git = "https://github.com/georust/rstar" } serde = { version = "1.0", features = ["derive"], optional = true } geo = "0.32.0" log = "0.4"