diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 9b32c3b7..427a4524 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -398,6 +398,7 @@ version = "2.0.0" dependencies = [ "criterion", "geo", + "lazy_static", "log", "map_3d", "thiserror", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 3fe29fa6..7885d151 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -37,6 +37,7 @@ thiserror = "1.0" [dev-dependencies] criterion = "0.5" +lazy_static = "1.4" [[bench]] name = "position" diff --git a/rust/src/mobility/quadtree.rs b/rust/src/mobility/quadtree.rs index 6dfa1350..742a5afa 100644 --- a/rust/src/mobility/quadtree.rs +++ b/rust/src/mobility/quadtree.rs @@ -1,3 +1,4 @@ +use crate::mobility::quadtree::quadkey::Quadkey; use std::f64::consts::PI; pub mod parse_error; @@ -13,6 +14,16 @@ const MAX_LONGITUDE: f64 = 180.; /// to represent a region that is at most 1m×1m in size const DEFAULT_DEPTH: u16 = 26; +/// Convenience struct to hold a list of quadkeys +/// +/// This is not a real tree representation but just a set of root-to-leaf branches +/// It might be interesting to look for en existing implementation of such a tree or to create one +pub type Quadtree = Vec; + +pub fn contains(quadtree: &Quadtree, quadkey: &Quadkey) -> bool { + quadtree.iter().any(|qk| quadkey <= qk) +} + fn coordinates_to_quadkey(latitude: f64, longitude: f64, depth: u16) -> String { tile_xy_to_quadkey( pixel_xy_to_tile_xy(coordinates_to_pixel_xy(latitude, longitude, depth)), @@ -94,6 +105,11 @@ fn tile_xy_to_quadkey(tile: TileXY, level_of_detail: u16) -> String { #[cfg(test)] mod tests { use crate::mobility::quadtree; + use crate::mobility::quadtree::quadkey::Quadkey; + use crate::mobility::quadtree::{contains, Quadtree}; + use std::str::FromStr; + + use lazy_static::lazy_static; fn position() -> (f64, f64) { (48.6263556, 2.2492123) @@ -133,4 +149,99 @@ mod tests { quadtree::coordinates_to_quadkey(latitude, longitude, 24), ) } + + lazy_static! { + static ref SHORT_ROOT_TREE: Quadtree = vec![Quadkey::from_str("12020").unwrap()]; + static ref DEEP_LEAVES_TREE: Quadtree = vec![ + Quadkey::from_str("12020322313211").unwrap(), + Quadkey::from_str("12020322313213").unwrap(), + Quadkey::from_str("12020322313302").unwrap(), + Quadkey::from_str("12020322313230").unwrap(), + Quadkey::from_str("12020322313221").unwrap(), + Quadkey::from_str("12020322313222").unwrap(), + Quadkey::from_str("120203223133032").unwrap(), + Quadkey::from_str("120203223133030").unwrap(), + Quadkey::from_str("120203223133012").unwrap(), + Quadkey::from_str("120203223133003").unwrap(), + Quadkey::from_str("120203223133002").unwrap(), + Quadkey::from_str("120203223133000").unwrap(), + Quadkey::from_str("120203223132103").unwrap(), + Quadkey::from_str("120203223132121").unwrap(), + Quadkey::from_str("120203223132123").unwrap(), + Quadkey::from_str("120203223132310").unwrap(), + Quadkey::from_str("120203223132311").unwrap(), + Quadkey::from_str("120203223132122").unwrap(), + Quadkey::from_str("120203223132033").unwrap(), + Quadkey::from_str("120203223132032").unwrap(), + Quadkey::from_str("120203223132023").unwrap(), + Quadkey::from_str("120203223132201").unwrap(), + Quadkey::from_str("120203223132203").unwrap(), + Quadkey::from_str("120203223132202").unwrap(), + Quadkey::from_str("120203223123313").unwrap(), + Quadkey::from_str("120203223123331").unwrap(), + Quadkey::from_str("120203223123333").unwrap(), + Quadkey::from_str("120203223132230").unwrap(), + Quadkey::from_str("1202032231330103").unwrap(), + Quadkey::from_str("12020322313300133").unwrap(), + Quadkey::from_str("12020322313301022").unwrap(), + Quadkey::from_str("12020322313301023").unwrap(), + ]; + } + + macro_rules! test_quadtree_contains { + ($test_name:ident, $tree:expr, $key:expr) => { + #[test] + fn $test_name() { + let contained = contains(&$tree, &$key); + + assert!(contained); + } + }; + } + test_quadtree_contains!( + several_deep_leaves_quadtree_contains_exact_quadkey, + DEEP_LEAVES_TREE, + Quadkey::from_str("12020322313301023").unwrap() + ); + test_quadtree_contains!( + several_deep_leaves_quadtree_contains_deeper_quadkey, + DEEP_LEAVES_TREE, + Quadkey::from_str("1202032231330102321").unwrap() + ); + test_quadtree_contains!( + short_root_only_tree_contains_exact_key, + SHORT_ROOT_TREE, + Quadkey::from_str("12020").unwrap() + ); + test_quadtree_contains!( + short_root_only_tree_contains_deeper_key, + SHORT_ROOT_TREE, + Quadkey::from_str("12020123").unwrap() + ); + + macro_rules! test_quadtree_does_not_contain { + ($test_name:ident, $tree:expr, $key:expr) => { + #[test] + fn $test_name() { + let contained = contains(&$tree, &$key); + + assert!(!contained); + } + }; + } + test_quadtree_does_not_contain!( + quadtree_does_not_contain_shorter_quadkey, + DEEP_LEAVES_TREE, + Quadkey::from_str("12020322").unwrap() + ); + test_quadtree_does_not_contain!( + quadtree_does_not_contain_same_depth_quadkey, + DEEP_LEAVES_TREE, + Quadkey::from_str("12020322313300130").unwrap() + ); + test_quadtree_does_not_contain!( + quadtree_does_not_contain_same_deeper_quadkey, + DEEP_LEAVES_TREE, + Quadkey::from_str("02020322313300130").unwrap() + ); }