#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum MapResolution {
#[default]
Low,
High,
}
const LOW: &[u8] = include_bytes!("world_110m.bin");
const HIGH: &[u8] = include_bytes!("world_50m.bin");
const BREAK: i16 = i16::MIN;
impl MapResolution {
fn data(self) -> &'static [u8] {
match self {
MapResolution::Low => LOW,
MapResolution::High => HIGH,
}
}
pub fn lines(self) -> Vec<Vec<(f64, f64)>> {
let mut lines = Vec::new();
let mut line = Vec::new();
for &[x0, x1, y0, y1] in self.data().as_chunks::<4>().0 {
let (x, y) = (i16::from_le_bytes([x0, x1]), i16::from_le_bytes([y0, y1]));
if x == BREAK && y == BREAK {
lines.push(std::mem::take(&mut line));
} else {
line.push((f64::from(x) / 100.0, f64::from(y) / 100.0));
}
}
lines.push(line);
lines.retain(|l| !l.is_empty());
lines
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_coastlines_are_in_range_and_sized_to_their_budget() {
for (resolution, budget) in [(MapResolution::Low, 1200), (MapResolution::High, 5000)] {
let lines = resolution.lines();
let points: usize = lines.iter().map(Vec::len).sum();
assert!(points > budget * 9 / 10 && points <= budget, "{points}");
for line in &lines {
assert!(line.len() >= 2);
for &(x, y) in line {
assert!((-180.0..=180.0).contains(&x) && (-90.0..=90.0).contains(&y));
}
}
}
assert!(LOW.len() < 8 * 1024 && HIGH.len() < 32 * 1024);
}
}