#![allow(clippy::pedantic, reason = "test/inspection tool")]
use std::collections::BTreeMap;
use std::path::Path;
use geo_types::Coord;
use insta::assert_binary_snapshot;
use map_tile_toolkit::{Slicer, TileId};
mod support;
use crate::support::{EXTENT, FixturePolygon};
fn buffers() -> [(u16, &'static str); 2] {
[(0, "polygons/snapshots"), (5, "polygons/snapshots-5")]
}
mod files {
use test_each_file::test_each_path;
test_each_path! { for ["geojson"] in "./tests/polygons/fixtures" => super::snapshot_polygon_fixture }
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct TiledFeature {
exterior: Vec<Coord<i32>>,
holes: Vec<Vec<Coord<i32>>>,
}
fn tiled(tile: TileId, rings: support::Rings) -> TiledFeature {
let origin = tile.origin(EXTENT).expect("tile in range");
let mut rings = rings
.into_iter()
.map(|ring| ring.into_iter().map(|c| c + origin).collect::<Vec<_>>());
TiledFeature {
exterior: rings.next().expect("exterior"),
holes: rings.collect(),
}
}
fn clip_tile(polygons: &[FixturePolygon], buffer: u16, tile: TileId) -> Vec<TiledFeature> {
let mut slicer = Slicer::<Coord<i32>>::new(EXTENT, buffer).expect("valid config");
support::tile_polygons(&mut slicer, polygons, tile)
.expect("clip")
.into_iter()
.map(|rings| tiled(tile, rings))
.collect()
}
fn clip_all_tiles(polygons: &[FixturePolygon], buffer: u16) -> BTreeMap<TileId, Vec<TiledFeature>> {
let rings: Vec<Vec<Coord<i32>>> = polygons.iter().map(|p| p.exterior.clone()).collect();
let (lo, hi) = support::padded_tile_span(&rings);
let mut out = BTreeMap::new();
for y in lo.y..=hi.y {
for x in lo.x..=hi.x {
let tile = TileId::new(x, y);
let piece = clip_tile(polygons, buffer, tile);
if !piece.is_empty() {
out.insert(tile, piece);
}
}
}
out
}
fn slice_all_tiles(
features: &[Vec<FixturePolygon>],
buffer: u16,
) -> BTreeMap<TileId, Vec<TiledFeature>> {
let mut slicer = Slicer::<Coord<i32>>::new(EXTENT, buffer).expect("valid config");
let mut out: BTreeMap<TileId, Vec<TiledFeature>> = BTreeMap::new();
for f in features {
for (tile, pieces) in support::slice_polygons(&mut slicer, f).expect("slice") {
out.entry(tile)
.or_default()
.extend(pieces.into_iter().map(|(_, rings)| tiled(tile, rings)));
}
}
out
}
fn duplicate_vertices(polygons: &[FixturePolygon]) -> Vec<FixturePolygon> {
let dup = |ring: &[Coord<i32>]| ring.iter().flat_map(|&c| [c, c]).collect::<Vec<_>>();
polygons
.iter()
.map(|p| FixturePolygon {
exterior: dup(&p.exterior),
holes: p.holes.iter().map(|h| dup(h)).collect(),
})
.collect()
}
fn snapshot_polygon_fixture([path]: [&Path; 1]) {
let stem = path.file_stem().and_then(|s| s.to_str()).expect("stem");
let features = support::load_polygon_features(path);
for (buffer, dir) in buffers() {
snapshot_at_buffer(stem, &features, buffer, dir);
}
}
fn snapshot_at_buffer(stem: &str, features: &[Vec<FixturePolygon>], buffer: u16, dir: &str) {
let polygons: Vec<FixturePolygon> = features.iter().flatten().cloned().collect();
let polygons = polygons.as_slice();
let per_tile = clip_all_tiles(polygons, buffer);
assert_eq!(
slice_all_tiles(features, buffer),
per_tile,
"Slicer::polygon and Slicer::tile_polygon differ for {stem} (buffer {buffer})"
);
let duped = clip_all_tiles(&duplicate_vertices(polygons), buffer);
assert_eq!(
duped, per_tile,
"duplicating every vertex changed the clip for {stem} (buffer {buffer})"
);
let mut features: Vec<_> = polygons
.iter()
.map(|p| support::input_polygon(&p.exterior, &p.holes))
.collect();
for (&tile, tile_features) in &per_tile {
for f in tile_features {
features.push(support::tile_polygon(&f.exterior, &f.holes, tile));
}
}
let bytes = support::feature_collection_bytes(features);
insta::with_settings!({
snapshot_path => dir,
prepend_module_to_snapshot => false,
}, {
let name = if buffer > 0 {
format!("{stem}-{buffer}.geojson")
} else {
format!("{stem}.geojson")
};
assert_binary_snapshot!(&name, bytes);
});
}