#![deny(warnings)]
use slippy_map_tilenames::tile2lonlat;
use std::f64::consts::PI;
use async_trait::async_trait;
use sqlx::PgPool;
#[async_trait]
pub trait TileSource: Sized {
async fn render_mvt(&self, pool: &PgPool, zoom: u8, x: i32, y: i32) -> Result<Vec<u8>, sqlx::Error>;
}
pub mod tm2;
static MAP_WIDTH_IN_METRES: f64 = 40_075_016.685_578_49;
static EPSG_3857_BOUNDS: f64 = 6_378_137_f64 * PI;
struct EPSG3857BBox {
north: f64,
west: f64,
south: f64,
east: f64,
}
fn epsg_4326_to_epsg_3857(lng: f64, lat: f64) -> (f64, f64) {
let y = ((90f64 + lat) * PI / 360f64).tan().ln() / (PI / 180f64);
(
lng * EPSG_3857_BOUNDS / 180f64,
y * EPSG_3857_BOUNDS / 180f64,
)
}
#[allow(clippy::many_single_char_names)]
fn get_epsg_3857_tile_bounds(
tile_px_width: i64,
zoom: u8,
x: i32,
y: i32,
buffer: i64,
) -> EPSG3857BBox {
let (w, n) = tile2lonlat(x as u32, y as u32, zoom);
let (e, s) = tile2lonlat((x + 1) as u32, (y + 1) as u32, zoom);
let (nw_3857_x, nw_3857_y) = epsg_4326_to_epsg_3857(w, n);
let (se_3857_x, se_3857_y) = epsg_4326_to_epsg_3857(e, s);
let map_width_in_px = (tile_px_width as f64) * 2f64.powf(zoom as f64);
let buffer_px_percentage = buffer as f64 / map_width_in_px;
let buffer_amt = buffer_px_percentage * MAP_WIDTH_IN_METRES;
EPSG3857BBox {
north: nw_3857_y + buffer_amt,
west: nw_3857_x - buffer_amt,
south: se_3857_y - buffer_amt,
east: se_3857_x + buffer_amt,
}
}
#[cfg(test)]
mod tests {
use super::*;
use assert_approx_eq::assert_approx_eq;
#[test]
fn test_get_tile_bounds() {
let computed_bounds = get_epsg_3857_tile_bounds(256, 0, 0, 0, 0);
let correct_bounds = EPSG3857BBox {
north: 20037508.342789244,
west: -20037508.342789244,
south: -20037508.342789255,
east: 20037508.342789244,
};
assert_approx_eq!(correct_bounds.north, computed_bounds.north);
let computed_bounds = get_epsg_3857_tile_bounds(256, 6, 33, 22, 0);
let correct_bounds = EPSG3857BBox {
north: 6261721.35712164,
west: 626172.1357121646,
south: 5635549.221409473,
east: 1252344.2714243291,
};
assert_approx_eq!(correct_bounds.north, computed_bounds.north);
let computed_bounds = get_epsg_3857_tile_bounds(256, 3, 4, 3, 256);
let correct_bounds = EPSG3857BBox {
north: 10018754.17139462,
west: -5009377.085697311,
south: -5009377.085697312,
east: 10018754.171394622,
};
assert_approx_eq!(correct_bounds.north, computed_bounds.north);
let computed_bounds = get_epsg_3857_tile_bounds(256, 6, 33, 22, 256);
let correct_bounds = EPSG3857BBox {
north: 6887893.492833803,
west: 0.00000000069849193096,
south: 5009377.085697309,
east: 1878516.407136493,
};
assert_approx_eq!(correct_bounds.north, computed_bounds.north);
}
}