#![allow(clippy::pedantic, reason = "test tool")]
use std::path::Path;
use geo::Validation;
use geo_types::{Coord, LineString, Polygon};
use map_tile_toolkit::{Slicer, TileId};
mod support;
use crate::support::{EXTENT, FixturePolygon};
mod files {
use test_each_file::test_each_path;
test_each_path! { for ["geojson"] in "./tests/polygons/fixtures" => super::pieces_are_valid }
}
fn as_polygon<R: AsRef<[Coord<i32>]>>(rings: &[R]) -> Polygon<f64> {
let line = |ring: &R| {
LineString::new(
ring.as_ref()
.iter()
.map(|c| Coord {
x: f64::from(c.x),
y: f64::from(c.y),
})
.collect(),
)
};
Polygon::new(line(&rings[0]), rings[1..].iter().map(line).collect())
}
fn pieces_are_valid([path]: [&Path; 1]) {
let polygons: Vec<FixturePolygon> = support::load_polygon_features(path)
.into_iter()
.flatten()
.collect();
let all_exteriors: Vec<Vec<Coord<i32>>> = polygons.iter().map(|p| p.exterior.clone()).collect();
let (lo, hi) = support::padded_tile_span(&all_exteriors);
let mut invalid = Vec::new();
for buffer in [0, 5] {
let mut slicer = Slicer::<Coord<i32>>::new(EXTENT, buffer).expect("valid config");
for (n, polygon) in polygons.iter().enumerate() {
let input = support::rings(polygon);
if as_polygon(&input).check_validation().is_err() {
continue;
}
for y in lo.y..=hi.y {
for x in lo.x..=hi.x {
let tile = TileId::new(x, y);
let Some(piece) = slicer.tile_polygon(tile, &input).expect("clip") else {
continue;
};
let rings: Vec<Vec<Coord<i32>>> = piece.rings().map(|r| r.to_vec()).collect();
if let Err(e) = as_polygon(&rings).check_validation() {
invalid.push(format!("buffer {buffer}, polygon {n}, tile {x},{y}: {e}"));
}
}
}
}
}
assert!(
invalid.is_empty(),
"{} invalid piece(s) from a valid polygon:\n{}",
invalid.len(),
invalid.join("\n")
);
}