#![allow(clippy::pedantic, reason = "profiling helper")]
use std::hint::black_box;
use std::time::Instant;
use geo::Simplify;
use geo_types::{Coord, LineString};
use map_tile_toolkit::SlicerAll;
use wkt::TryFromWkt;
const EARTH_CIRCUMFERENCE: f64 = 40_075_016.686;
const HALF: f64 = EARTH_CIRCUMFERENCE / 2.0;
const EXTENT: u32 = 4096;
const SIMPLIFY_PIXELS: f64 = 3.0;
fn main() {
let mut args = std::env::args().skip(1);
let path = args
.next()
.expect("usage: simplify_slice <path-to.wkt> <zoom>");
let zoom: u32 = args
.next()
.expect("usage: simplify_slice <path-to.wkt> <zoom>")
.parse()
.expect("zoom must be a non-negative integer");
let tile_count = 2f64.powi(i32::try_from(zoom).expect("zoom fits i32"));
let divisor = EARTH_CIRCUMFERENCE / tile_count;
let pixel_m = divisor / f64::from(EXTENT);
let epsilon = SIMPLIFY_PIXELS * pixel_m;
let units_per_m = f64::from(EXTENT) / divisor;
eprintln!(
"zoom {zoom}: divisor {divisor:.3} m/tile, pixel {pixel_m:.4} m, simplify epsilon {epsilon:.4} m"
);
let t = Instant::now();
let text = std::fs::read_to_string(&path).expect("readable WKT file");
let lines: Vec<LineString<f64>> = text
.lines()
.filter(|l| !l.trim().is_empty())
.map(|l| LineString::try_from_wkt_str(l).expect("valid WKT LINESTRING"))
.collect();
eprintln!("loaded {} geometries in {:?}", lines.len(), t.elapsed());
let t = Instant::now();
let geoms: Vec<LineString<i32>> = lines
.iter()
.map(|ls| {
let simplified = ls.simplify(epsilon);
let coords: Vec<Coord<i32>> = simplified
.0
.iter()
.map(|c| Coord {
x: ((c.x + HALF) * units_per_m) as i32,
y: ((HALF - c.y) * units_per_m) as i32,
})
.collect();
LineString(coords)
})
.collect();
let vertices: usize = geoms.iter().map(|ls| ls.0.len()).sum();
eprintln!(
"simplified + projected to {vertices} vertices in {:?}",
t.elapsed()
);
let t = Instant::now();
let mut tiles = 0u64;
let mut skipped = 0u64;
let mut acc = SlicerAll::new(EXTENT, 0).expect("valid slicer config");
for geom in &geoms {
if acc.add_feature(black_box(geom.0.as_slice())).is_err() {
skipped += 1;
}
}
let mut pieces = 0u64;
for tile in acc.iter_tiles() {
black_box(tile.tile_id());
for feature in tile.iter_features() {
for polyline in feature.iter_polylines() {
black_box(polyline);
pieces += 1;
}
}
tiles += 1;
}
black_box(pieces);
eprintln!(
"sliced {} geometries into {tiles} tiles / {pieces} pieces ({skipped} skipped) in {:?}",
geoms.len(),
t.elapsed()
);
}