diff --git a/snapr/src/builder.rs b/snapr/src/builder.rs index 81bc8c0..4912058 100644 --- a/snapr/src/builder.rs +++ b/snapr/src/builder.rs @@ -1,6 +1,6 @@ use std::fmt; -use crate::{Error, Snapr, TileFetcher}; +use crate::{Error, Snapr, TileFetcher, Zoom}; /// Builder structure for [`snapr`]. /// @@ -26,8 +26,7 @@ pub struct SnaprBuilder<'a> { tile_size: Option, height: Option, width: Option, - zoom: Option, - max_zoom: Option, + zoom: Option, } impl<'a> SnaprBuilder<'a> { @@ -69,17 +68,9 @@ impl<'a> SnaprBuilder<'a> { } /// Configures the `zoom` to be used in the [`Snapr::zoom`] field. - pub fn with_zoom(self, zoom: u8) -> Self { + pub fn with_zoom>(self, zoom: Z) -> Self { Self { - zoom: Some(zoom), - ..self - } - } - - /// Configures the `max_zoom` to be used in the [`Snapr::max_zoom`] field. - pub fn with_max_zoom(self, max_zoom: u8) -> Self { - Self { - max_zoom: Some(max_zoom), + zoom: Some(zoom.into()), ..self } } @@ -113,8 +104,7 @@ impl<'a> SnaprBuilder<'a> { let tile_size = self.tile_size.unwrap_or(256); let height = self.height.unwrap_or(600); let width = self.width.unwrap_or(800); - let zoom = self.zoom; - let max_zoom = self.max_zoom.unwrap_or(17); + let zoom = self.zoom.unwrap_or_default(); let snapr = Snapr { tile_fetcher, @@ -122,7 +112,6 @@ impl<'a> SnaprBuilder<'a> { height, width, zoom, - max_zoom, }; Ok(snapr) diff --git a/snapr/src/lib.rs b/snapr/src/lib.rs index fc1152a..d35875c 100644 --- a/snapr/src/lib.rs +++ b/snapr/src/lib.rs @@ -1,6 +1,10 @@ #![doc = include_str!("../README.md")] -use std::{f64::consts::PI, fmt}; +use std::{ + f64::consts::PI, + fmt, + ops::{Deref, DerefMut}, +}; use drawing::{Context, Drawable}; use geo::{BoundingRect, Centroid, Coord, MapCoords}; @@ -44,6 +48,49 @@ pub enum Error { Unknown(#[from] anyhow::Error), } +/// Used by [`Snapr`] to determine how the zoom level is calculated when generating snapshots. +#[derive(Clone, Copy, Debug, Hash, PartialEq)] +pub enum Zoom { + /// Specifies that the zoom level should be automatically derived from the geometry extents. + /// Contains an inner [`u8`] that controls the max zoom level. + Automatic(u8), + + /// Specifies that the zoom level should be constant across all snapshots. + Constant(u8), +} + +impl Deref for Zoom { + type Target = u8; + + fn deref(&self) -> &Self::Target { + match self { + Self::Automatic(inner) => inner, + Self::Constant(inner) => inner, + } + } +} + +impl DerefMut for Zoom { + fn deref_mut(&mut self) -> &mut Self::Target { + match self { + Self::Automatic(inner) => inner, + Self::Constant(inner) => inner, + } + } +} + +impl Default for Zoom { + fn default() -> Self { + Zoom::Automatic(17) + } +} + +impl From for Zoom { + fn from(value: u8) -> Self { + Zoom::Constant(value) + } +} + /// Utility structure to generate snapshots. /// Should be normally constructed through building with [`SnaprBuilder`]. pub struct Snapr<'a> { @@ -61,10 +108,7 @@ pub struct Snapr<'a> { width: u32, /// Zoom level of generated snapshots. - zoom: Option, - - /// Maximum zoom level of generated snapshots. - max_zoom: u8, + zoom: Zoom, } impl<'a> Snapr<'a> { @@ -113,9 +157,9 @@ impl<'a> Snapr<'a> { }; let zoom = match self.zoom { - Some(zoom) => zoom.clamp(1, self.max_zoom), - None => match geometries.bounding_rect() { - Some(bounding_box) => self.zoom_from_geometries(bounding_box), + Zoom::Constant(level) => level, + Zoom::Automatic(max_level) => match geometries.bounding_rect() { + Some(bounding_box) => self.zoom_from_geometries(bounding_box, max_level), None => todo!("Return an `Err` or find a suitable default for `bounding_box`"), }, }; @@ -162,10 +206,10 @@ impl<'a> Snapr<'a> { impl<'a> Snapr<'a> { /// Calculates the [`zoom`](Self::zoom) level to use when [`zoom`](Self::zoom) itself is [`None`]. - fn zoom_from_geometries(&self, bounding_box: geo::Rect) -> u8 { + fn zoom_from_geometries(&self, bounding_box: geo::Rect, max_zoom: u8) -> u8 { let mut zoom = 1; - for level in (0..=self.max_zoom).rev() { + for level in (0..=max_zoom).rev() { let bounding_box = bounding_box.map_coords(|coords| { let converted = Self::epsg_4326_to_epsg_3857(level, geo::Point::from(coords));