use rstar::RTree;
mod structs;
pub use structs::*;
mod validation;
mod conv;
mod relates;
mod rtrees;
use rtrees::FakeRegion;
#[derive(Debug)]
pub struct SpatialIndex {
small: SplitGeoSeq,
point_tree: RTree<FakeRegion>,
line_tree: RTree<FakeRegion>,
poly_tree: RTree<FakeRegion>,
ls_tree: RTree<FakeRegion>,
rect_tree: RTree<FakeRegion>,
tri_tree: RTree<FakeRegion>,
config: Config,
}
#[cfg(feature = "parallel")]
pub struct ParSpatialIndex(SpatialIndex);
mod index;
#[cfg(test)]
mod naive;
#[cfg(test)]
mod proptests;
#[cfg(test)]
mod tests {
use std::convert::TryInto;
use geo::Point;
use pretty_assertions::assert_eq;
#[cfg(feature = "parallel")]
use rayon::prelude::*;
use super::*;
use index::*;
pub fn test_prox_map<Small, Big, E1, E2>(
config: Config,
small: Small,
big: Big,
expected: &Vec<ProxMapRow>,
) where
Small: TryInto<SplitGeoSeq, Error = E1> + Clone,
Big: TryInto<SplitGeoSeq, Error = E2> + Clone,
E1: std::any::Any + std::fmt::Debug,
E2: std::any::Any + std::fmt::Debug,
{
let small_geoms = sgs_try_into(small.clone())
.expect("small conversion")
.to_vec();
let big_geoms = sgs_try_into(big.clone()).expect("big conversion").to_vec();
let expected_geoms: Vec<_> = expected
.iter()
.map(|pmr| ProxMapGeoRow {
big_index: pmr.big_index,
small_index: pmr.small_index,
distance: pmr.distance,
big: big_geoms[pmr.big_index].clone(),
small: small_geoms[pmr.small_index].clone(),
})
.collect();
let _expected_geoms2 = expected_geoms.clone();
let si = config
.clone()
.serial(small.clone())
.expect("construction succeeded");
let mut actual = si.proximity_map(big.clone()).unwrap().collect::<Vec<_>>();
actual.sort();
assert_eq!(actual, *expected);
let mut actual_geoms = si
.proximity_map_with_geos(big.clone())
.unwrap()
.collect::<Vec<_>>();
actual_geoms.sort();
assert_eq!(actual_geoms, expected_geoms);
}
#[cfg(feature = "parallel")]
pub fn test_par_prox_map<Small, Big, E1, E2>(
config: Config,
small: Small,
big: Big,
expected: &Vec<ProxMapRow>,
) where
Small: TryInto<Par<SplitGeoSeq>, Error = E1> + Clone,
Big: TryInto<Par<SplitGeoSeq>, Error = E2> + Clone,
E1: std::any::Any + std::fmt::Debug,
E2: std::any::Any + std::fmt::Debug,
{
let small_geoms = par_sgs_try_into(small.clone())
.expect("small conversion")
.to_vec();
let big_geoms = par_sgs_try_into(big.clone())
.expect("big conversion")
.to_vec();
let expected_geoms: Vec<_> = expected
.iter()
.map(|pmr| ProxMapGeoRow {
big_index: pmr.big_index,
small_index: pmr.small_index,
distance: pmr.distance,
big: big_geoms[pmr.big_index].clone(),
small: small_geoms[pmr.small_index].clone(),
})
.collect();
let _expected_geoms2 = expected_geoms.clone();
let si = config
.clone()
.parallel(small.clone())
.expect("construction succeeded");
let mut actual = si.proximity_map(big.clone()).unwrap().collect::<Vec<_>>();
actual.sort();
assert_eq!(actual, *expected);
let mut actual_geoms = si
.proximity_map_with_geos(big.clone())
.unwrap()
.collect::<Vec<_>>();
actual_geoms.sort();
assert_eq!(actual_geoms, expected_geoms);
}
pub fn test_spatial_join<Small, Big, E1, E2>(
config: Config,
small: Small,
big: Big,
interaction: Interaction,
expected: &Vec<SJoinRow>,
) where
Small: TryInto<SplitGeoSeq, Error = E1> + Clone,
Big: TryInto<SplitGeoSeq, Error = E2> + Clone,
E1: std::any::Any + std::fmt::Debug,
E2: std::any::Any + std::fmt::Debug,
{
let small_geoms = sgs_try_into(small.clone())
.expect("small conversion")
.to_vec();
let big_geoms = sgs_try_into(big.clone()).expect("big conversion").to_vec();
let expected_geoms: Vec<_> = expected
.iter()
.map(|sjr| SJoinGeoRow {
big_index: sjr.big_index,
small_index: sjr.small_index,
big: big_geoms[sjr.big_index].clone(),
small: small_geoms[sjr.small_index].clone(),
})
.collect();
let _expected_geoms2 = expected_geoms.clone();
let si = config
.clone()
.serial(small.clone())
.expect("construction succeeded");
let mut actual = si
.spatial_join(big.clone(), interaction)
.unwrap()
.collect::<Vec<_>>();
actual.sort();
assert_eq!(actual, *expected);
let mut actual_geoms = si
.spatial_join_with_geos(big.clone(), interaction)
.unwrap()
.collect::<Vec<_>>();
actual_geoms.sort();
assert_eq!(actual_geoms, expected_geoms);
}
#[cfg(feature = "parallel")]
pub fn test_par_spatial_join<Small, Big, E1, E2>(
config: Config,
small: Small,
big: Big,
interaction: Interaction,
expected: &Vec<SJoinRow>,
) where
Small: TryInto<Par<SplitGeoSeq>, Error = E1> + Clone,
Big: TryInto<Par<SplitGeoSeq>, Error = E2> + Clone,
E1: std::any::Any + std::fmt::Debug,
E2: std::any::Any + std::fmt::Debug,
{
let small_geoms = par_sgs_try_into(small.clone())
.expect("small conversion")
.to_vec();
let big_geoms = par_sgs_try_into(big.clone())
.expect("big conversion")
.to_vec();
let expected_geoms: Vec<_> = expected
.iter()
.map(|sjr| SJoinGeoRow {
big_index: sjr.big_index,
small_index: sjr.small_index,
big: big_geoms[sjr.big_index].clone(),
small: small_geoms[sjr.small_index].clone(),
})
.collect();
let _expected_geoms2 = expected_geoms.clone();
let si = config
.clone()
.parallel(small.clone())
.expect("construction succeeded");
let mut actual = si
.spatial_join(big.clone(), interaction)
.unwrap()
.collect::<Vec<_>>();
actual.sort();
assert_eq!(actual, *expected);
let mut actual_geoms = si
.spatial_join_with_geos(big.clone(), interaction)
.unwrap()
.collect::<Vec<_>>();
actual_geoms.sort();
assert_eq!(actual_geoms, expected_geoms);
}
#[test]
fn simple_index_self() {
let config = Config::new().max_distance(4.);
let small = vec![Point::new(1., 1.)];
let big = vec![Point::new(1., 1.)];
let expected = vec![ProxMapRow {
big_index: 0,
small_index: 0,
distance: 0.,
}];
test_prox_map(config, small.clone(), big.clone(), &expected);
#[cfg(feature = "parallel")]
test_par_prox_map(config, small, big, &expected);
}
#[test]
fn self_spatial_join_pair() {
let config = Config::new();
let pts = vec![
geo::Geometry::Point(Point::new(1., 1.)),
geo::Geometry::Point(Point::new(22., 22.)),
];
let expected = vec![
SJoinRow {
big_index: 0,
small_index: 0,
},
SJoinRow {
big_index: 1,
small_index: 1,
},
];
test_spatial_join(config, &pts, &pts, Interaction::Intersects, &expected);
#[cfg(feature = "parallel")]
test_par_spatial_join(config, &pts, &pts, Interaction::Intersects, &expected);
}
#[test]
fn simple_index_some_other() {
let config = Config::new().max_distance(4.);
let small = vec![Point::new(1., 1.)];
let big = vec![Point::new(2., 1.)];
let expected = vec![ProxMapRow {
big_index: 0,
small_index: 0,
distance: 1.0,
}];
test_prox_map(config, small.clone(), big.clone(), &expected);
#[cfg(feature = "parallel")]
test_par_prox_map(config, small, big, &expected);
}
#[test]
fn simple_index_none() {
let config = Config::new().max_distance(0.5);
let small = vec![Point::new(1., 1.)];
let big = vec![Point::new(2., 1.)];
let expected = vec![];
test_prox_map(config, small.clone(), big.clone(), &expected);
#[cfg(feature = "parallel")]
test_par_prox_map(config, small, big, &expected);
}
}