Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Zoom Enum #21

Merged
merged 1 commit into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 5 additions & 16 deletions snapr/src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::fmt;

use crate::{Error, Snapr, TileFetcher};
use crate::{Error, Snapr, TileFetcher, Zoom};

/// Builder structure for [`snapr`].
///
Expand All @@ -26,8 +26,7 @@ pub struct SnaprBuilder<'a> {
tile_size: Option<u32>,
height: Option<u32>,
width: Option<u32>,
zoom: Option<u8>,
max_zoom: Option<u8>,
zoom: Option<Zoom>,
}

impl<'a> SnaprBuilder<'a> {
Expand Down Expand Up @@ -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<Z: Into<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
}
}
Expand Down Expand Up @@ -113,16 +104,14 @@ 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,
tile_size,
height,
width,
zoom,
max_zoom,
};

Ok(snapr)
Expand Down
64 changes: 54 additions & 10 deletions snapr/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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<u8> 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> {
Expand All @@ -61,10 +108,7 @@ pub struct Snapr<'a> {
width: u32,

/// Zoom level of generated snapshots.
zoom: Option<u8>,

/// Maximum zoom level of generated snapshots.
max_zoom: u8,
zoom: Zoom,
}

impl<'a> Snapr<'a> {
Expand Down Expand Up @@ -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`"),
},
};
Expand Down Expand Up @@ -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));

Expand Down
Loading