From 77fc560b25e9a80c192adc3e3f5d4bd26a7584c9 Mon Sep 17 00:00:00 2001 From: Yaroslav Biletskyi Date: Mon, 30 May 2022 10:18:40 +0300 Subject: [PATCH 1/5] add struct for zoom level --- maplibre/src/context.rs | 4 +- maplibre/src/coords.rs | 129 +++++++++++++++++-------- maplibre/src/io/geometry_index.rs | 6 +- maplibre/src/io/shared_thread_state.rs | 4 +- 4 files changed, 96 insertions(+), 47 deletions(-) diff --git a/maplibre/src/context.rs b/maplibre/src/context.rs index 96b77630a..c5a58941a 100644 --- a/maplibre/src/context.rs +++ b/maplibre/src/context.rs @@ -1,4 +1,4 @@ -use crate::coords::{Zoom, TILE_SIZE}; +use crate::coords::{Zoom, TILE_SIZE, ZoomLevel}; use crate::io::shared_thread_state::SharedThreadState; use crate::io::tile_cache::TileCache; use crate::io::TessellateMessage; @@ -43,7 +43,7 @@ impl ViewState { self.camera.calc_view_proj(&self.perspective) } - pub fn visible_level(&self) -> u8 { + pub fn visible_level(&self) -> ZoomLevel { self.zoom.level() } diff --git a/maplibre/src/coords.rs b/maplibre/src/coords.rs index 38194904b..2cd20873a 100644 --- a/maplibre/src/coords.rs +++ b/maplibre/src/coords.rs @@ -33,12 +33,12 @@ const fn create_zoom_bounds() -> [u32; DIM] { /// /// TODO: We can optimize the quadkey and store the keys on 2 bits instead of 8 #[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Copy)] -pub struct Quadkey([u8; MAX_ZOOM]); +pub struct Quadkey([ZoomLevel; MAX_ZOOM]); impl Quadkey { - pub fn new(quad_encoded: &[u8]) -> Self { - let mut key = [0u8; MAX_ZOOM]; - key[0] = quad_encoded.len() as u8; + pub fn new(quad_encoded: &[ZoomLevel]) -> Self { + let mut key = [ZoomLevel::default(); MAX_ZOOM]; + key[0] = ZoomLevel::new(quad_encoded.len() as u8); for (i, part) in quad_encoded.iter().enumerate() { key[i + 1] = *part; } @@ -48,7 +48,7 @@ impl Quadkey { impl fmt::Debug for Quadkey { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let len = self.0[0] as usize; + let len = self.0[0].0 as usize; for part in &self.0[0..len] { write!(f, "{:?}", part)?; } @@ -56,6 +56,51 @@ impl fmt::Debug for Quadkey { } } +#[derive(Ord, PartialOrd, Eq, PartialEq, Hash, Copy, Clone, Debug)] +pub struct ZoomLevel(u8); + +impl ZoomLevel { + pub fn new(zoom_level: u8) -> Self { + ZoomLevel(zoom_level) + } +} + +impl Default for ZoomLevel { + fn default() -> Self { + ZoomLevel(0) + } +} + +impl std::ops::Add for ZoomLevel { + type Output = ZoomLevel; + + fn add(self, rhs: i32) -> Self::Output { + ZoomLevel(self.0 + rhs as u8) + } +} + +impl std::ops::Sub for ZoomLevel { + type Output = ZoomLevel; + + fn sub(self, rhs: i32) -> Self::Output { + ZoomLevel(self.0 - rhs as u8) + } +} + +impl std::ops::Mul for ZoomLevel { + type Output = ZoomLevel; + + fn mul(self, rhs: i32) -> Self::Output { + ZoomLevel(self.0 * rhs as u8) + } +} + +impl fmt::Display for ZoomLevel { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + /// `Zoom` is an exponential scale that defines the zoom of the camera on the map. /// We can derive the `ZoomLevel` from `Zoom` by using the `[crate::coords::ZOOM_BOUNDS]`. #[derive(Copy, Clone, Debug)] @@ -67,6 +112,12 @@ impl Zoom { } } +impl Zoom { + pub fn from(zoom_level: ZoomLevel) -> Self { + Zoom(zoom_level.0 as f64) + } +} + impl Default for Zoom { fn default() -> Self { Zoom(0.0) @@ -97,19 +148,19 @@ impl std::ops::Sub for Zoom { impl Zoom { pub fn scale_to_tile(&self, coords: &WorldTileCoords) -> f64 { - 2.0_f64.powf(coords.z as f64 - self.0) + 2.0_f64.powf(coords.z.0 as f64 - self.0) } - pub fn scale_to_zoom_level(&self, z: u8) -> f64 { - 2.0_f64.powf(z as f64 - self.0) + pub fn scale_to_zoom_level(&self, z: ZoomLevel) -> f64 { + 2.0_f64.powf(z.0 as f64 - self.0) } pub fn scale_delta(&self, zoom: &Zoom) -> f64 { 2.0_f64.powf(zoom.0 - self.0) } - pub fn level(&self) -> u8 { - self.0.floor() as u8 + pub fn level(&self) -> ZoomLevel { + ZoomLevel::new(self.0.floor() as u8) } } @@ -144,7 +195,7 @@ pub struct InnerCoords { pub struct TileCoords { pub x: u32, pub y: u32, - pub z: u8, + pub z: ZoomLevel, } impl TileCoords { @@ -158,7 +209,7 @@ impl TileCoords { pub fn into_world_tile(self, scheme: TileAddressingScheme) -> Option { // FIXME: MAX_ZOOM is 32, which means max bound is 2^32, which wouldn't fit in u32 or i32 // Note that unlike WorldTileCoords, values are signed (no idea why) - let bounds = ZOOM_BOUNDS[self.z as usize] as i32; + let bounds = ZOOM_BOUNDS[self.z.0 as usize] as i32; let x = self.x as i32; let y = self.y as i32; @@ -182,7 +233,7 @@ impl From<(u32, u32, u8)> for TileCoords { TileCoords { x: tuple.0, y: tuple.1, - z: tuple.2, + z: ZoomLevel::new(tuple.2), } } } @@ -198,7 +249,7 @@ impl From<(u32, u32, u8)> for TileCoords { pub struct WorldTileCoords { pub x: i32, pub y: i32, - pub z: u8, + pub z: ZoomLevel, } impl WorldTileCoords { @@ -211,7 +262,7 @@ impl WorldTileCoords { /// `x=5,y=5` at zoom level `z=0`. pub fn into_tile(self, scheme: TileAddressingScheme) -> Option { // FIXME: MAX_ZOOM is 32, which means max bound is 2^32, which wouldn't fit in u32 or i32 - let bounds = ZOOM_BOUNDS[self.z as usize]; + let bounds = ZOOM_BOUNDS[self.z.0 as usize]; let x = self.x as u32; let y = self.y as u32; @@ -239,7 +290,7 @@ impl WorldTileCoords { If tile.z > zoom: => scale < 512 */ - let tile_scale = TILE_SIZE * Zoom::new(self.z as f64).scale_delta(&zoom); + let tile_scale = TILE_SIZE * Zoom::from(self.z).scale_delta(&zoom); let translate = Matrix4::from_translation(Vector3::new( self.x as f64 * tile_scale, @@ -264,7 +315,7 @@ impl WorldTileCoords { /// Adopted from [tilebelt](https://github.com/mapbox/tilebelt) pub fn build_quad_key(&self) -> Option { - let bounds = ZOOM_BOUNDS[self.z as usize]; + let bounds = ZOOM_BOUNDS[self.z.0 as usize]; let x = self.x as u32; let y = self.y as u32; @@ -272,11 +323,11 @@ impl WorldTileCoords { return None; } - let mut key = [0u8; MAX_ZOOM]; + let mut key = [ZoomLevel::default(); MAX_ZOOM]; key[0] = self.z; - for z in 1..self.z + 1 { + for z in 1..self.z.0 + 1 { let mut b = 0; let mask: i32 = 1 << (z - 1); if (self.x & mask) != 0 { @@ -285,7 +336,7 @@ impl WorldTileCoords { if (self.y & mask) != 0 { b += 2u8; } - key[z as usize] = b; + key[z as usize] = ZoomLevel::new(b); } Some(Quadkey(key)) } @@ -318,7 +369,7 @@ impl WorldTileCoords { /// Get the tile which is one zoom level lower and contains this one pub fn get_parent(&self) -> Option { - if self.z == 0 { + if self.z == ZoomLevel::default() { return None; } @@ -335,7 +386,7 @@ impl From<(i32, i32, u8)> for WorldTileCoords { WorldTileCoords { x: tuple.0, y: tuple.1, - z: tuple.2, + z: ZoomLevel::new(tuple.2), } } } @@ -402,7 +453,7 @@ impl WorldCoords { Self { x, y } } - pub fn into_world_tile(self, z: u8, zoom: Zoom) -> WorldTileCoords { + pub fn into_world_tile(self, z: ZoomLevel, zoom: Zoom) -> WorldTileCoords { let tile_scale = zoom.scale_to_zoom_level(z) / TILE_SIZE; // TODO: Deduplicate let x = self.x * tile_scale; let y = self.y * tile_scale; @@ -447,12 +498,12 @@ impl From> for WorldCoords { pub struct ViewRegion { min_tile: WorldTileCoords, max_tile: WorldTileCoords, - z: u8, + z: ZoomLevel, padding: i32, } impl ViewRegion { - pub fn new(view_region: Aabb2, padding: i32, zoom: Zoom, z: u8) -> Self { + pub fn new(view_region: Aabb2, padding: i32, zoom: Zoom, z: ZoomLevel) -> Self { let min_world: WorldCoords = WorldCoords::at_ground(view_region.min.x, view_region.min.y); let min_world_tile: WorldTileCoords = min_world.into_world_tile(z, zoom); let max_world: WorldCoords = WorldCoords::at_ground(view_region.max.x, view_region.max.y); @@ -466,7 +517,7 @@ impl ViewRegion { } } - pub fn zoom_level(&self) -> u8 { + pub fn zoom_level(&self) -> ZoomLevel { self.z } @@ -481,7 +532,7 @@ impl ViewRegion { pub fn iter(&self) -> impl Iterator + '_ { (self.min_tile.x - self.padding..self.max_tile.x + 1 + self.padding).flat_map(move |x| { (self.min_tile.y - self.padding..self.max_tile.y + 1 + self.padding).map(move |y| { - let tile_coord: WorldTileCoords = (x, y, self.z as u8).into(); + let tile_coord: WorldTileCoords = (x, y, self.z.0 as u8).into(); tile_coord }) }) @@ -489,7 +540,7 @@ impl ViewRegion { } impl fmt::Display for TileCoords { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "T(x={x},y={y},z={z})", @@ -523,9 +574,7 @@ mod tests { use crate::style::source::TileAddressingScheme; - use crate::coords::{ - Quadkey, TileCoords, ViewRegion, WorldCoords, WorldTileCoords, Zoom, EXTENT, - }; + use crate::coords::{Quadkey, TileCoords, ViewRegion, WorldCoords, WorldTileCoords, Zoom, EXTENT, ZoomLevel}; use crate::util::math::Aabb2; const TOP_LEFT: Vector4 = Vector4::new(0.0, 0.0, 0.0, 1.0); @@ -553,32 +602,32 @@ mod tests { #[test] fn test_quad_key() { assert_eq!( - TileCoords { x: 0, y: 0, z: 1 } + TileCoords { x: 0, y: 0, z: ZoomLevel::new(1) } .into_world_tile(TileAddressingScheme::TMS) .unwrap() .build_quad_key(), - Some(Quadkey::new(&[2])) + Some(Quadkey::new(&[ZoomLevel::new(2)])) ); assert_eq!( - TileCoords { x: 0, y: 1, z: 1 } + TileCoords { x: 0, y: 1, z: ZoomLevel::new(1) } .into_world_tile(TileAddressingScheme::TMS) .unwrap() .build_quad_key(), - Some(Quadkey::new(&[0])) + Some(Quadkey::new(&[ZoomLevel::new(0)])) ); assert_eq!( - TileCoords { x: 1, y: 1, z: 1 } + TileCoords { x: 1, y: 1, z: ZoomLevel::new(1) } .into_world_tile(TileAddressingScheme::TMS) .unwrap() .build_quad_key(), - Some(Quadkey::new(&[1])) + Some(Quadkey::new(&[ZoomLevel::new(1)])) ); assert_eq!( - TileCoords { x: 1, y: 0, z: 1 } + TileCoords { x: 1, y: 0, z: ZoomLevel::new(1) } .into_world_tile(TileAddressingScheme::TMS) .unwrap() .build_quad_key(), - Some(Quadkey::new(&[3])) + Some(Quadkey::new(&[ZoomLevel::new(3)])) ); } @@ -588,7 +637,7 @@ mod tests { Aabb2::new(Point2::new(0.0, 0.0), Point2::new(2000.0, 2000.0)), 1, Zoom::default(), - 0, + ZoomLevel::default(), ) .iter() { diff --git a/maplibre/src/io/geometry_index.rs b/maplibre/src/io/geometry_index.rs index 6febc93a6..a3eece6ce 100644 --- a/maplibre/src/io/geometry_index.rs +++ b/maplibre/src/io/geometry_index.rs @@ -11,7 +11,7 @@ use geozero::geo_types::GeoWriter; use geozero::{ColumnValue, FeatureProcessor, GeomProcessor, PropertyProcessor}; use rstar::{Envelope, PointDistance, RTree, RTreeObject, AABB}; -use crate::coords::{InnerCoords, Quadkey, WorldCoords, WorldTileCoords, Zoom, EXTENT, TILE_SIZE}; +use crate::coords::{InnerCoords, Quadkey, WorldCoords, WorldTileCoords, Zoom, EXTENT, TILE_SIZE, ZoomLevel}; use crate::util::math::bounds_from_points; /// A quad tree storing the currently loaded tiles. @@ -35,7 +35,7 @@ impl GeometryIndex { pub fn query_point( &self, world_coords: &WorldCoords, - z: u8, + z: ZoomLevel, zoom: Zoom, ) -> Option>> { let world_tile_coords = world_coords.into_world_tile(z, zoom); @@ -44,7 +44,7 @@ impl GeometryIndex { .build_quad_key() .and_then(|key| self.index.get(&key)) { - let scale = zoom.scale_delta(&Zoom::new(z as f64)); // FIXME: can be wrong, if tiles of different z are visible + let scale = zoom.scale_delta(&Zoom::from(z)); // FIXME: can be wrong, if tiles of different z are visible let delta_x = world_coords.x / TILE_SIZE * scale - world_tile_coords.x as f64; let delta_y = world_coords.y / TILE_SIZE * scale - world_tile_coords.y as f64; diff --git a/maplibre/src/io/shared_thread_state.rs b/maplibre/src/io/shared_thread_state.rs index 97e9fdeba..ccc46ef26 100644 --- a/maplibre/src/io/shared_thread_state.rs +++ b/maplibre/src/io/shared_thread_state.rs @@ -1,6 +1,6 @@ //! Shared thread state. -use crate::coords::{WorldCoords, WorldTileCoords, Zoom}; +use crate::coords::{WorldCoords, WorldTileCoords, Zoom, ZoomLevel}; use crate::error::Error; use crate::io::geometry_index::{GeometryIndex, IndexProcessor, IndexedGeometry, TileIndex}; use crate::io::tile_request_state::TileRequestState; @@ -150,7 +150,7 @@ impl SharedThreadState { pub fn query_point( &self, world_coords: &WorldCoords, - z: u8, + z: ZoomLevel, zoom: Zoom, ) -> Option>> { if let Ok(geometry_index) = self.geometry_index.lock() { From de9d17e007feaa9e7aa95b410c2fb82b2030e8c4 Mon Sep 17 00:00:00 2001 From: Yaroslav Biletskyi Date: Mon, 30 May 2022 11:37:01 +0300 Subject: [PATCH 2/5] fix linter errors --- maplibre/src/context.rs | 2 +- maplibre/src/coords.rs | 52 +++++++++++++++++++++---------- maplibre/src/io/geometry_index.rs | 4 ++- 3 files changed, 39 insertions(+), 19 deletions(-) diff --git a/maplibre/src/context.rs b/maplibre/src/context.rs index c5a58941a..66d342077 100644 --- a/maplibre/src/context.rs +++ b/maplibre/src/context.rs @@ -1,4 +1,4 @@ -use crate::coords::{Zoom, TILE_SIZE, ZoomLevel}; +use crate::coords::{Zoom, ZoomLevel, TILE_SIZE}; use crate::io::shared_thread_state::SharedThreadState; use crate::io::tile_cache::TileCache; use crate::io::TessellateMessage; diff --git a/maplibre/src/coords.rs b/maplibre/src/coords.rs index 2cd20873a..0d5352a63 100644 --- a/maplibre/src/coords.rs +++ b/maplibre/src/coords.rs @@ -574,7 +574,9 @@ mod tests { use crate::style::source::TileAddressingScheme; - use crate::coords::{Quadkey, TileCoords, ViewRegion, WorldCoords, WorldTileCoords, Zoom, EXTENT, ZoomLevel}; + use crate::coords::{ + Quadkey, TileCoords, ViewRegion, WorldCoords, WorldTileCoords, Zoom, ZoomLevel, EXTENT, + }; use crate::util::math::Aabb2; const TOP_LEFT: Vector4 = Vector4::new(0.0, 0.0, 0.0, 1.0); @@ -602,31 +604,47 @@ mod tests { #[test] fn test_quad_key() { assert_eq!( - TileCoords { x: 0, y: 0, z: ZoomLevel::new(1) } - .into_world_tile(TileAddressingScheme::TMS) - .unwrap() - .build_quad_key(), + TileCoords { + x: 0, + y: 0, + z: ZoomLevel::new(1) + } + .into_world_tile(TileAddressingScheme::TMS) + .unwrap() + .build_quad_key(), Some(Quadkey::new(&[ZoomLevel::new(2)])) ); assert_eq!( - TileCoords { x: 0, y: 1, z: ZoomLevel::new(1) } - .into_world_tile(TileAddressingScheme::TMS) - .unwrap() - .build_quad_key(), + TileCoords { + x: 0, + y: 1, + z: ZoomLevel::new(1) + } + .into_world_tile(TileAddressingScheme::TMS) + .unwrap() + .build_quad_key(), Some(Quadkey::new(&[ZoomLevel::new(0)])) ); assert_eq!( - TileCoords { x: 1, y: 1, z: ZoomLevel::new(1) } - .into_world_tile(TileAddressingScheme::TMS) - .unwrap() - .build_quad_key(), + TileCoords { + x: 1, + y: 1, + z: ZoomLevel::new(1) + } + .into_world_tile(TileAddressingScheme::TMS) + .unwrap() + .build_quad_key(), Some(Quadkey::new(&[ZoomLevel::new(1)])) ); assert_eq!( - TileCoords { x: 1, y: 0, z: ZoomLevel::new(1) } - .into_world_tile(TileAddressingScheme::TMS) - .unwrap() - .build_quad_key(), + TileCoords { + x: 1, + y: 0, + z: ZoomLevel::new(1) + } + .into_world_tile(TileAddressingScheme::TMS) + .unwrap() + .build_quad_key(), Some(Quadkey::new(&[ZoomLevel::new(3)])) ); } diff --git a/maplibre/src/io/geometry_index.rs b/maplibre/src/io/geometry_index.rs index a3eece6ce..2537a682c 100644 --- a/maplibre/src/io/geometry_index.rs +++ b/maplibre/src/io/geometry_index.rs @@ -11,7 +11,9 @@ use geozero::geo_types::GeoWriter; use geozero::{ColumnValue, FeatureProcessor, GeomProcessor, PropertyProcessor}; use rstar::{Envelope, PointDistance, RTree, RTreeObject, AABB}; -use crate::coords::{InnerCoords, Quadkey, WorldCoords, WorldTileCoords, Zoom, EXTENT, TILE_SIZE, ZoomLevel}; +use crate::coords::{ + InnerCoords, Quadkey, WorldCoords, WorldTileCoords, Zoom, ZoomLevel, EXTENT, TILE_SIZE, +}; use crate::util::math::bounds_from_points; /// A quad tree storing the currently loaded tiles. From 174db63088f83ae46521330cbfe06cb5b93dfd78 Mon Sep 17 00:00:00 2001 From: Yaroslav Biletskyi Date: Mon, 30 May 2022 11:55:09 +0300 Subject: [PATCH 3/5] fix build errors --- maplibre/src/coords.rs | 6 ++++++ maplibre/src/render/tile_view_pattern.rs | 5 +++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/maplibre/src/coords.rs b/maplibre/src/coords.rs index 0d5352a63..4db9393f6 100644 --- a/maplibre/src/coords.rs +++ b/maplibre/src/coords.rs @@ -101,6 +101,12 @@ impl fmt::Display for ZoomLevel { } } +impl Into for ZoomLevel { + fn into(self) -> u8 { + self.0 + } +} + /// `Zoom` is an exponential scale that defines the zoom of the camera on the map. /// We can derive the `ZoomLevel` from `Zoom` by using the `[crate::coords::ZOOM_BOUNDS]`. #[derive(Copy, Clone, Debug)] diff --git a/maplibre/src/render/tile_view_pattern.rs b/maplibre/src/render/tile_view_pattern.rs index 2b7aaf0c1..371576bf4 100644 --- a/maplibre/src/render/tile_view_pattern.rs +++ b/maplibre/src/render/tile_view_pattern.rs @@ -167,13 +167,14 @@ impl, B> TileViewPattern { } pub fn stencil_reference_value(&self, world_coords: &WorldTileCoords) -> u8 { - world_coords.z * 5 + let zoom_level = world_coords.z * 5 + match (world_coords.x, world_coords.y) { (x, y) if x % 2 == 0 && y % 2 == 0 => 2, (x, y) if x % 2 == 0 && y % 2 != 0 => 1, (x, y) if x % 2 != 0 && y % 2 == 0 => 4, (x, y) if x % 2 != 0 && y % 2 != 0 => 3, _ => unreachable!(), - } + }; + return zoom_level.into(); } } From b5e6f878739fb81c7c7f2f146003883469638636 Mon Sep 17 00:00:00 2001 From: Yaroslav Biletskyi Date: Wed, 1 Jun 2022 10:48:30 +0300 Subject: [PATCH 4/5] fixed for PR comments --- maplibre/src/coords.rs | 65 ++++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/maplibre/src/coords.rs b/maplibre/src/coords.rs index 4db9393f6..f31b6f4b8 100644 --- a/maplibre/src/coords.rs +++ b/maplibre/src/coords.rs @@ -38,7 +38,7 @@ pub struct Quadkey([ZoomLevel; MAX_ZOOM]); impl Quadkey { pub fn new(quad_encoded: &[ZoomLevel]) -> Self { let mut key = [ZoomLevel::default(); MAX_ZOOM]; - key[0] = ZoomLevel::new(quad_encoded.len() as u8); + key[0] = (quad_encoded.len() as u8).into(); for (i, part) in quad_encoded.iter().enumerate() { key[i + 1] = *part; } @@ -48,7 +48,9 @@ impl Quadkey { impl fmt::Debug for Quadkey { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let len = self.0[0].0 as usize; + let key = self.0; + let ZoomLevel(level) = key[0]; + let len = level as usize; for part in &self.0[0..len] { write!(f, "{:?}", part)?; } @@ -60,8 +62,8 @@ impl fmt::Debug for Quadkey { pub struct ZoomLevel(u8); impl ZoomLevel { - pub fn new(zoom_level: u8) -> Self { - ZoomLevel(zoom_level) + pub fn is_root(self) -> bool { + return self.0 == 0; } } @@ -75,7 +77,8 @@ impl std::ops::Add for ZoomLevel { type Output = ZoomLevel; fn add(self, rhs: i32) -> Self::Output { - ZoomLevel(self.0 + rhs as u8) + let zoom_level = self.0.checked_add(rhs as u8).unwrap(); + ZoomLevel(zoom_level) } } @@ -83,7 +86,8 @@ impl std::ops::Sub for ZoomLevel { type Output = ZoomLevel; fn sub(self, rhs: i32) -> Self::Output { - ZoomLevel(self.0 - rhs as u8) + let zoom_level = self.0.checked_sub(rhs as u8).unwrap(); + ZoomLevel(zoom_level) } } @@ -91,7 +95,8 @@ impl std::ops::Mul for ZoomLevel { type Output = ZoomLevel; fn mul(self, rhs: i32) -> Self::Output { - ZoomLevel(self.0 * rhs as u8) + let zoom_level = self.0.checked_mul(rhs as u8).unwrap(); + ZoomLevel(zoom_level) } } @@ -101,6 +106,12 @@ impl fmt::Display for ZoomLevel { } } +impl From for ZoomLevel { + fn from(zoom_level: u8) -> Self { + ZoomLevel(zoom_level) + } +} + impl Into for ZoomLevel { fn into(self) -> u8 { self.0 @@ -166,7 +177,7 @@ impl Zoom { } pub fn level(&self) -> ZoomLevel { - ZoomLevel::new(self.0.floor() as u8) + ZoomLevel::from(self.0.floor() as u8) } } @@ -239,7 +250,7 @@ impl From<(u32, u32, u8)> for TileCoords { TileCoords { x: tuple.0, y: tuple.1, - z: ZoomLevel::new(tuple.2), + z: ZoomLevel::from(tuple.2), } } } @@ -342,7 +353,7 @@ impl WorldTileCoords { if (self.y & mask) != 0 { b += 2u8; } - key[z as usize] = ZoomLevel::new(b); + key[z as usize] = ZoomLevel::from(b); } Some(Quadkey(key)) } @@ -375,7 +386,7 @@ impl WorldTileCoords { /// Get the tile which is one zoom level lower and contains this one pub fn get_parent(&self) -> Option { - if self.z == ZoomLevel::default() { + if self.z.is_root() { return None; } @@ -387,12 +398,12 @@ impl WorldTileCoords { } } -impl From<(i32, i32, u8)> for WorldTileCoords { - fn from(tuple: (i32, i32, u8)) -> Self { +impl From<(i32, i32, ZoomLevel)> for WorldTileCoords { + fn from(tuple: (i32, i32, ZoomLevel)) -> Self { WorldTileCoords { x: tuple.0, y: tuple.1, - z: ZoomLevel::new(tuple.2), + z: tuple.2, } } } @@ -538,7 +549,7 @@ impl ViewRegion { pub fn iter(&self) -> impl Iterator + '_ { (self.min_tile.x - self.padding..self.max_tile.x + 1 + self.padding).flat_map(move |x| { (self.min_tile.y - self.padding..self.max_tile.y + 1 + self.padding).map(move |y| { - let tile_coord: WorldTileCoords = (x, y, self.z.0 as u8).into(); + let tile_coord: WorldTileCoords = (x, y, self.z).into(); tile_coord }) }) @@ -588,7 +599,7 @@ mod tests { const TOP_LEFT: Vector4 = Vector4::new(0.0, 0.0, 0.0, 1.0); const BOTTOM_RIGHT: Vector4 = Vector4::new(EXTENT, EXTENT, 0.0, 1.0); - fn to_from_world(tile: (i32, i32, u8), zoom: Zoom) { + fn to_from_world(tile: (i32, i32, ZoomLevel), zoom: Zoom) { let tile = WorldTileCoords::from(tile); let p1 = tile.transform_for_zoom(zoom) * TOP_LEFT; let p2 = tile.transform_for_zoom(zoom) * BOTTOM_RIGHT; @@ -602,9 +613,9 @@ mod tests { #[test] fn world_coords_tests() { - to_from_world((1, 0, 1), Zoom::new(1.0)); - to_from_world((67, 42, 7), Zoom::new(7.0)); - to_from_world((17421, 11360, 15), Zoom::new(15.0)); + to_from_world((1, 0, ZoomLevel::from(1)), Zoom::new(1.0)); + to_from_world((67, 42, ZoomLevel::from(7)), Zoom::new(7.0)); + to_from_world((17421, 11360, ZoomLevel::from(15)), Zoom::new(15.0)); } #[test] @@ -613,45 +624,45 @@ mod tests { TileCoords { x: 0, y: 0, - z: ZoomLevel::new(1) + z: ZoomLevel::from(1) } .into_world_tile(TileAddressingScheme::TMS) .unwrap() .build_quad_key(), - Some(Quadkey::new(&[ZoomLevel::new(2)])) + Some(Quadkey::new(&[ZoomLevel::from(2)])) ); assert_eq!( TileCoords { x: 0, y: 1, - z: ZoomLevel::new(1) + z: ZoomLevel::from(1) } .into_world_tile(TileAddressingScheme::TMS) .unwrap() .build_quad_key(), - Some(Quadkey::new(&[ZoomLevel::new(0)])) + Some(Quadkey::new(&[ZoomLevel::from(0)])) ); assert_eq!( TileCoords { x: 1, y: 1, - z: ZoomLevel::new(1) + z: ZoomLevel::from(1) } .into_world_tile(TileAddressingScheme::TMS) .unwrap() .build_quad_key(), - Some(Quadkey::new(&[ZoomLevel::new(1)])) + Some(Quadkey::new(&[ZoomLevel::from(1)])) ); assert_eq!( TileCoords { x: 1, y: 0, - z: ZoomLevel::new(1) + z: ZoomLevel::from(1) } .into_world_tile(TileAddressingScheme::TMS) .unwrap() .build_quad_key(), - Some(Quadkey::new(&[ZoomLevel::new(3)])) + Some(Quadkey::new(&[ZoomLevel::from(3)])) ); } From cbfa5e938dcd0b7bd2cdac4022bf25bf9cc1765f Mon Sep 17 00:00:00 2001 From: Maximilian Ammann Date: Wed, 1 Jun 2022 12:54:36 +0200 Subject: [PATCH 5/5] Simplify stencil_reference_value, the z does not need to be taken into account --- maplibre/src/coords.rs | 21 ++++++--------------- maplibre/src/render/tile_view_pattern.rs | 16 +++++++--------- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/maplibre/src/coords.rs b/maplibre/src/coords.rs index f31b6f4b8..151b46176 100644 --- a/maplibre/src/coords.rs +++ b/maplibre/src/coords.rs @@ -73,29 +73,20 @@ impl Default for ZoomLevel { } } -impl std::ops::Add for ZoomLevel { +impl std::ops::Add for ZoomLevel { type Output = ZoomLevel; - fn add(self, rhs: i32) -> Self::Output { - let zoom_level = self.0.checked_add(rhs as u8).unwrap(); + fn add(self, rhs: u8) -> Self::Output { + let zoom_level = self.0.checked_add(rhs).unwrap(); ZoomLevel(zoom_level) } } -impl std::ops::Sub for ZoomLevel { +impl std::ops::Sub for ZoomLevel { type Output = ZoomLevel; - fn sub(self, rhs: i32) -> Self::Output { - let zoom_level = self.0.checked_sub(rhs as u8).unwrap(); - ZoomLevel(zoom_level) - } -} - -impl std::ops::Mul for ZoomLevel { - type Output = ZoomLevel; - - fn mul(self, rhs: i32) -> Self::Output { - let zoom_level = self.0.checked_mul(rhs as u8).unwrap(); + fn sub(self, rhs: u8) -> Self::Output { + let zoom_level = self.0.checked_sub(rhs).unwrap(); ZoomLevel(zoom_level) } } diff --git a/maplibre/src/render/tile_view_pattern.rs b/maplibre/src/render/tile_view_pattern.rs index 371576bf4..6a14ef0b7 100644 --- a/maplibre/src/render/tile_view_pattern.rs +++ b/maplibre/src/render/tile_view_pattern.rs @@ -167,14 +167,12 @@ impl, B> TileViewPattern { } pub fn stencil_reference_value(&self, world_coords: &WorldTileCoords) -> u8 { - let zoom_level = world_coords.z * 5 - + match (world_coords.x, world_coords.y) { - (x, y) if x % 2 == 0 && y % 2 == 0 => 2, - (x, y) if x % 2 == 0 && y % 2 != 0 => 1, - (x, y) if x % 2 != 0 && y % 2 == 0 => 4, - (x, y) if x % 2 != 0 && y % 2 != 0 => 3, - _ => unreachable!(), - }; - return zoom_level.into(); + match (world_coords.x, world_coords.y) { + (x, y) if x % 2 == 0 && y % 2 == 0 => 2, + (x, y) if x % 2 == 0 && y % 2 != 0 => 1, + (x, y) if x % 2 != 0 && y % 2 == 0 => 4, + (x, y) if x % 2 != 0 && y % 2 != 0 => 3, + _ => unreachable!(), + } } }