#![allow(clippy::pedantic, reason = "test tool")]
use std::collections::BTreeMap;
use geo_types::Coord;
use map_tile_toolkit::{Measured, Mosaic, PolygonSlice, Slicer, TileError, TileId, Vertex};
mod support;
use crate::support::EXTENT;
fn slice_all_runs<V: Vertex>(poly: &[V]) -> BTreeMap<TileId, Vec<Vec<V>>> {
let slicer = Slicer::<V>::new(10, 0).expect("valid config");
let mut tiles: BTreeMap<TileId, Vec<Vec<V>>> = BTreeMap::new();
for s in slicer.line(poly).expect("slice") {
tiles.entry(s.tile()).or_default().push(s.run().to_vec());
}
tiles
}
fn measured_line() -> Vec<Measured<u32>> {
vec![
Measured::new(5, 5, 10), Measured::new(5, 15, 20), Measured::new(5, 25, 30), ]
}
#[test]
fn line_payload_survives_slicing_and_the_mosaic() {
let tiles = slice_all_runs(&measured_line());
assert_eq!(
tiles[&TileId::new(0, 1)],
vec![vec![
Measured::new(5, -5, 10),
Measured::new(5, 5, 20),
Measured::new(5, 15, 30),
]]
);
let plain = vec![
Coord { x: 5, y: 5 },
Coord { x: 5, y: 15 },
Coord { x: 5, y: 25 },
];
let positions: BTreeMap<TileId, Vec<Vec<Coord<i32>>>> = tiles
.iter()
.map(|(t, runs)| {
let runs = runs
.iter()
.map(|r| r.iter().map(|v| v.position).collect())
.collect();
(*t, runs)
})
.collect();
assert_eq!(positions, slice_all_runs(&plain));
let mut mosaic = Mosaic::new(10).expect("valid config");
for (tile, runs) in tiles {
mosaic
.add(tile, runs.as_slice())
.expect("self-consistent tiles never conflict");
}
let features: Vec<Vec<Measured<u32>>> = mosaic.iter_features().collect();
assert_eq!(features, vec![measured_line()]);
}
#[test]
fn mosaic_rejects_a_payload_mismatch() {
let mut mosaic = Mosaic::new(10).expect("valid config");
mosaic
.add(
TileId::new(0, 0),
&[vec![Measured::new(5, 5, 10), Measured::new(5, 15, 20)]],
)
.expect("first tile");
let bad = mosaic.add(
TileId::new(0, 1),
&[vec![Measured::new(5, -5, 10), Measured::new(5, 5, 999)]],
);
assert_eq!(bad, Err(TileError::Conflict(vec![TileId::new(0, 0)])));
assert_eq!(mosaic.len(), 1);
assert!(mosaic.contains(TileId::new(0, 0)));
}
#[test]
fn point_payload_rides_into_every_tile_of_the_point() {
let s = Slicer::new(10, 2).expect("config");
let pts = [Measured::new(9, 5, 'a'), Measured::new(15, 15, 'b')];
let got: Vec<_> = pts
.iter()
.flat_map(|&p| s.point(p).expect("point").map(|p| (p.tile(), p.point())))
.collect();
assert_eq!(
got,
[
(TileId::new(0, 0), Measured::new(9, 5, 'a')),
(TileId::new(1, 0), Measured::new(-1, 5, 'a')),
(TileId::new(1, 1), Measured::new(5, 5, 'b')),
]
);
}
#[test]
fn polygon_payload_rides_through_pieces_and_fill() {
let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("tests/polygons/fixtures/big_fill.geojson");
let polygons = support::load_polygon_fixture(&path);
let mut m = 0;
let mut measured = |ring: &[Coord<i32>]| -> Vec<Measured<u32>> {
ring.iter()
.map(|c| {
m += 1;
Measured::new(c.x, c.y, m)
})
.collect()
};
let rings: Vec<Vec<Vec<Measured<u32>>>> = polygons
.iter()
.map(|p| {
std::iter::once(measured(&p.exterior))
.chain(p.holes.iter().map(|h| measured(h)))
.collect()
})
.collect();
let mut slicer = Slicer::<Measured<u32>>::new(EXTENT, 3).expect("config");
type Rings = Vec<Vec<Measured<u32>>>;
let mut pieces: BTreeMap<TileId, Vec<Rings>> = BTreeMap::new();
let mut runs = 0;
for polygon in &rings {
let mut slices = slicer.polygon(polygon).expect("slice");
while let Some(slice) = slices.next() {
match slice.expect("slice") {
PolygonSlice::Piece(piece) => pieces
.entry(piece.tile())
.or_default()
.push(piece.rings().map(|r| r.to_vec()).collect()),
PolygonSlice::Run(_) => runs += 1,
}
}
}
assert!(runs > 0, "the fixture has covered tiles");
for (&tile, got) in &pieces {
let mut expected: Vec<Rings> = Vec::new();
for polygon in &rings {
if let Some(piece) = slicer.tile_polygon(tile, polygon).expect("clip") {
expected.push(piece.rings().map(|r| r.to_vec()).collect());
}
}
assert_eq!(got, &expected, "{tile:?}");
}
}