mod earth;
mod moon;
pub mod data;
use crate::hatch::Hatch;
use crate::strokes::Stroke;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Basemap {
EarthCoastlines,
EarthBorders,
EarthTropics,
MoonMaria,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Resolution {
Schematic,
#[default]
Low,
High,
}
#[derive(Debug, Clone)]
pub struct Feature {
pub name: &'static str,
pub closed: bool,
pub points: &'static [(f64, f64)],
}
pub fn features(layer: Basemap, resolution: Resolution) -> Vec<&'static Feature> {
match layer {
Basemap::EarthCoastlines => earth_coastlines(resolution),
Basemap::EarthBorders => earth_borders(resolution),
Basemap::EarthTropics => earth::TROPICS.iter().collect(),
Basemap::MoonMaria => moon::MARIA.iter().collect(),
}
}
fn earth_coastlines(resolution: Resolution) -> Vec<&'static Feature> {
match resolution {
Resolution::Schematic => earth::COASTLINES_SCHEMATIC.iter().collect(),
Resolution::Low => data::coastline_110m::FEATURES.iter().collect(),
Resolution::High => {
#[cfg(feature = "high-res-basemaps")]
{
data::coastline_50m::FEATURES.iter().collect()
}
#[cfg(not(feature = "high-res-basemaps"))]
{
data::coastline_110m::FEATURES.iter().collect()
}
}
}
}
fn earth_borders(resolution: Resolution) -> Vec<&'static Feature> {
match resolution {
Resolution::Schematic => earth::BORDERS_SCHEMATIC.iter().collect(),
Resolution::Low => data::countries_110m::FEATURES.iter().collect(),
Resolution::High => {
#[cfg(feature = "high-res-basemaps")]
{
data::countries_50m::FEATURES.iter().collect()
}
#[cfg(not(feature = "high-res-basemaps"))]
{
data::countries_110m::FEATURES.iter().collect()
}
}
}
}
#[derive(Debug, Clone)]
pub struct BasemapOpts {
pub(crate) resolution: Resolution,
pub(crate) stroke: Stroke,
pub(crate) stroke_width: f64,
pub(crate) hatch: Option<Hatch>,
pub(crate) only: Option<Vec<String>>,
pub(crate) except: Option<Vec<String>>,
}
impl Default for BasemapOpts {
fn default() -> Self {
Self {
resolution: Resolution::Low,
stroke: Stroke::Solid,
stroke_width: 0.8,
hatch: None,
only: None,
except: None,
}
}
}
impl BasemapOpts {
pub fn resolution(mut self, r: Resolution) -> Self {
self.resolution = r;
self
}
pub fn stroke(mut self, s: Stroke) -> Self {
self.stroke = s;
self
}
pub fn stroke_width(mut self, w: f64) -> Self {
self.stroke_width = w;
self
}
pub fn hatch(mut self, h: Hatch) -> Self {
self.hatch = Some(h);
self
}
pub fn only<S: Into<String>>(mut self, names: impl IntoIterator<Item = S>) -> Self {
self.only = Some(names.into_iter().map(|n| n.into()).collect());
self
}
pub fn except<S: Into<String>>(mut self, names: impl IntoIterator<Item = S>) -> Self {
self.except = Some(names.into_iter().map(|n| n.into()).collect());
self
}
}
pub(crate) fn filter_features<'a>(
features: Vec<&'a Feature>,
only: &Option<Vec<String>>,
except: &Option<Vec<String>>,
) -> Vec<&'a Feature> {
features
.into_iter()
.filter(|f| match only {
Some(names) => names.iter().any(|n| n == f.name),
None => true,
})
.filter(|f| match except {
Some(names) => !names.iter().any(|n| n == f.name),
None => true,
})
.collect()
}