From ebe83035c2a1c4c2f167e5b9c95a787673f43b65 Mon Sep 17 00:00:00 2001 From: sharkAndshark Date: Fri, 15 Dec 2023 16:44:18 +0800 Subject: [PATCH 01/19] Add wgs84_to_webmercator to tile util --- martin-tile-utils/src/lib.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/martin-tile-utils/src/lib.rs b/martin-tile-utils/src/lib.rs index efbbfa9c0..e78d362de 100644 --- a/martin-tile-utils/src/lib.rs +++ b/martin-tile-utils/src/lib.rs @@ -248,6 +248,13 @@ pub fn webmercator_to_wgs84(x: f64, y: f64) -> (f64, f64) { (lng, lat) } +pub fn wgs84_to_webmercator(lon: f64, lat: f64) -> (f64, f64) { + let x = PI * 6378137.0 * lon / 180.0; + let y = ((90.0 + lat) * PI / 360.0).tan().ln() / (PI / 180.0); + let y = PI * 6378137.0 * y / 180.0; + (x, y) +} + #[cfg(test)] mod tests { #![allow(clippy::unreadable_literal)] From d140f4e043e8167351bd88f9982e621370908c59 Mon Sep 17 00:00:00 2001 From: sharkAndshark Date: Fri, 15 Dec 2023 16:45:43 +0800 Subject: [PATCH 02/19] Add tile_colrow to tile-util --- martin-tile-utils/src/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/martin-tile-utils/src/lib.rs b/martin-tile-utils/src/lib.rs index e78d362de..b9b67043a 100644 --- a/martin-tile-utils/src/lib.rs +++ b/martin-tile-utils/src/lib.rs @@ -204,6 +204,14 @@ pub fn tile_index(lon: f64, lat: f64, zoom: u8) -> (u32, u32) { (tile.x.min(max_value) as u32, tile.y.min(max_value) as u32) } +pub fn tile_colrow(lng: f64, lat: f64, zoom: u8) -> (u64, u64) { + let tile_size = EARTH_CIRCUMFERENCE / f64::from(1_u32 << zoom); + let (x, y) = wgs84_to_webmercator(lng, lat); + let col = ((x - (EARTH_CIRCUMFERENCE * -0.5)).abs() / tile_size).trunc() as u64; + let row = (((EARTH_CIRCUMFERENCE * 0.5) - y).abs() / tile_size).trunc() as u64; + (col, row) +} + /// Convert min/max XYZ tile coordinates to a bounding box values. /// The result is `[min_lng, min_lat, max_lng, max_lat]` #[must_use] From 2581bff44ab0f00d65c683bcb7f43b399fd51e8f Mon Sep 17 00:00:00 2001 From: sharkAndshark Date: Fri, 15 Dec 2023 16:46:52 +0800 Subject: [PATCH 03/19] Add bbox_to_colrow to tile-util --- martin-tile-utils/src/lib.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/martin-tile-utils/src/lib.rs b/martin-tile-utils/src/lib.rs index b9b67043a..a9a53cfff 100644 --- a/martin-tile-utils/src/lib.rs +++ b/martin-tile-utils/src/lib.rs @@ -235,6 +235,18 @@ pub fn bbox_to_xyz(left: f64, bottom: f64, right: f64, top: f64, zoom: u8) -> (u (min_x, min_y, max_x, max_y) } +pub fn bbox_to_colrow( + left: f64, + bottom: f64, + right: f64, + top: f64, + zoom: u8, +) -> (u64, u64, u64, u64) { + let (min_col, min_row) = tile_colrow(left, top, zoom); + let (max_col, max_row) = tile_colrow(right, bottom, zoom); + (min_col, min_row, max_col, max_row) +} + /// Compute precision of a zoom level, i.e. how many decimal digits of the longitude and latitude are relevant #[must_use] #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] From e33c787705a187517eadd7b70eb0483d4ca2fac0 Mon Sep 17 00:00:00 2001 From: sharkAndshark Date: Fri, 15 Dec 2023 16:52:46 +0800 Subject: [PATCH 04/19] Use bbox_to_colrow --- martin-tile-utils/Cargo.toml | 1 + martin-tile-utils/src/lib.rs | 51 +++++++++++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/martin-tile-utils/Cargo.toml b/martin-tile-utils/Cargo.toml index 6ed71e7d4..8b55fe125 100644 --- a/martin-tile-utils/Cargo.toml +++ b/martin-tile-utils/Cargo.toml @@ -21,3 +21,4 @@ tile-grid.workspace = true [dev-dependencies] approx.workspace = true +insta = { workspace = true, features = ["toml", "yaml"] } diff --git a/martin-tile-utils/src/lib.rs b/martin-tile-utils/src/lib.rs index a9a53cfff..34c9be7b3 100644 --- a/martin-tile-utils/src/lib.rs +++ b/martin-tile-utils/src/lib.rs @@ -284,6 +284,7 @@ mod tests { use approx::assert_relative_eq; use Encoding::{Internal, Uncompressed}; use Format::{Jpeg, Json, Png, Webp}; + use insta::assert_snapshot; use super::*; @@ -334,7 +335,7 @@ mod tests { assert_relative_eq!(bbox[2], 179.99999999999986, epsilon = f64::EPSILON * 2.0); assert_relative_eq!(bbox[3], 85.05112877980655, epsilon = f64::EPSILON * 2.0); - let xyz = bbox_to_xyz(bbox[0], bbox[1], bbox[2], bbox[3], 0); + let xyz = bbox_to_colrow(bbox[0], bbox[1], bbox[2], bbox[3], 0); assert_eq!(xyz, (0, 0, 0, 0)); let bbox = xyz_to_bbox(1, 0, 0, 0, 0); @@ -347,7 +348,7 @@ mod tests { ); assert_relative_eq!(bbox[3], 85.05112877980655, epsilon = f64::EPSILON * 2.0); - let xyz = bbox_to_xyz(bbox[0], bbox[1], bbox[2], bbox[3], 1); + let xyz = bbox_to_colrow(bbox[0], bbox[1], bbox[2], bbox[3], 1); assert!(xyz.0 == 0 || xyz.0 == 1); assert!(xyz.1 == 0); assert!(xyz.2 == 0 || xyz.2 == 1); @@ -359,7 +360,7 @@ mod tests { assert_relative_eq!(bbox[2], -146.2499999999996, epsilon = f64::EPSILON * 2.0); assert_relative_eq!(bbox[3], 83.979259498862, epsilon = f64::EPSILON * 2.0); - let xyz = bbox_to_xyz(bbox[0], bbox[1], bbox[2], bbox[3], 5); + let xyz = bbox_to_colrow(bbox[0], bbox[1], bbox[2], bbox[3], 5); assert!(xyz.0 == 1 || xyz.0 == 2); assert!(xyz.1 == 0 || xyz.1 == 1); assert!(xyz.2 == 2 || xyz.2 == 3); @@ -371,13 +372,55 @@ mod tests { assert_relative_eq!(bbox[2], -146.2499999999996, epsilon = f64::EPSILON * 2.0); assert_relative_eq!(bbox[3], 81.09321385260832, epsilon = f64::EPSILON * 2.0); - let xyz = bbox_to_xyz(bbox[0], bbox[1], bbox[2], bbox[3], 5); + let xyz = bbox_to_colrow(bbox[0], bbox[1], bbox[2], bbox[3], 5); assert!(xyz.0 == 1 || xyz.0 == 2); assert!(xyz.1 == 2 || xyz.1 == 3); assert!(xyz.2 == 2 || xyz.2 == 3); assert!(xyz.3 == 5 || xyz.3 == 6); } + #[test] + fn test_box() { + fn tst(left: f64, bottom: f64, right: f64, top: f64, zoom: u8) -> String { + let (x0, y0, x1, y1) = bbox_to_colrow(left, bottom, right, top, zoom); + format!("({x0}, {y0}, {x1}, {y1})") + } + + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 0), @"(0, 0, 0, 0)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 1), @"(0, 1, 0, 1)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 2), @"(0, 3, 0, 3)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 3), @"(0, 7, 0, 7)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 4), @"(0, 14, 1, 15)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 5), @"(0, 29, 2, 31)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 6), @"(0, 58, 5, 63)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 7), @"(0, 116, 11, 126)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 8), @"(0, 233, 23, 253)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 9), @"(0, 466, 47, 507)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 10), @"(1, 933, 94, 1014)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 11), @"(3, 1866, 188, 2029)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 12), @"(6, 3732, 377, 4059)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 13), @"(12, 7465, 755, 8119)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 14), @"(25, 14931, 1510, 16239)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 15), @"(51, 29863, 3020, 32479)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 16), @"(102, 59727, 6041, 64958)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 17), @"(204, 119455, 12083, 129917)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 18), @"(409, 238911, 24166, 259834)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 19), @"(819, 477823, 48332, 519669)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 20), @"(1638, 955647, 96665, 1039339)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 21), @"(3276, 1911295, 193331, 2078678)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 22), @"(6553, 3822590, 386662, 4157356)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 23), @"(13107, 7645181, 773324, 8314713)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 24), @"(26214, 15290363, 1546649, 16629427)"); + + // All these are incorrect + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 25), @"(33554431, 33554431, 33554431, 33554431)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 26), @"(67108863, 67108863, 67108863, 67108863)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 27), @"(134217727, 134217727, 134217727, 134217727)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 28), @"(268435455, 268435455, 268435455, 268435455)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 29), @"(536870911, 536870911, 536870911, 536870911)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 30), @"(1073741823, 1073741823, 1073741823, 1073741823)"); + } + #[test] fn meter_to_lng_lat() { let (lng, lat) = webmercator_to_wgs84(-20037508.34, -20037508.34); From 1ba2d92b906d765d0cc1f3703d073043eae8daa0 Mon Sep 17 00:00:00 2001 From: sharkAndshark Date: Fri, 15 Dec 2023 17:29:54 +0800 Subject: [PATCH 05/19] Update test --- martin-tile-utils/src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/martin-tile-utils/src/lib.rs b/martin-tile-utils/src/lib.rs index 34c9be7b3..b76f9871a 100644 --- a/martin-tile-utils/src/lib.rs +++ b/martin-tile-utils/src/lib.rs @@ -413,12 +413,12 @@ mod tests { assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 24), @"(26214, 15290363, 1546649, 16629427)"); // All these are incorrect - assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 25), @"(33554431, 33554431, 33554431, 33554431)"); - assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 26), @"(67108863, 67108863, 67108863, 67108863)"); - assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 27), @"(134217727, 134217727, 134217727, 134217727)"); - assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 28), @"(268435455, 268435455, 268435455, 268435455)"); - assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 29), @"(536870911, 536870911, 536870911, 536870911)"); - assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 30), @"(1073741823, 1073741823, 1073741823, 1073741823)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 25), @"(52428, 30580726, 3093299, 33258855)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 26), @"(104857, 61161453, 6186598, 66517711)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 27), @"(209715, 122322907, 12373196, 133035423)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 28), @"(419430, 244645814, 24746393, 266070846)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 29), @"(838860, 489291628, 49492787, 532141692)"); + assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 30), @"(1677721, 978583256, 98985574, 1064283385)"); } #[test] From c3b4c42f90a52fc278f1a814ce0ce14a2ac4e8bb Mon Sep 17 00:00:00 2001 From: sharkAndshark Date: Fri, 15 Dec 2023 17:36:03 +0800 Subject: [PATCH 06/19] Rename bbox_to_colrow to bbox_to_xyz and use u32 --- martin-tile-utils/src/lib.rs | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/martin-tile-utils/src/lib.rs b/martin-tile-utils/src/lib.rs index b76f9871a..2232bddc4 100644 --- a/martin-tile-utils/src/lib.rs +++ b/martin-tile-utils/src/lib.rs @@ -204,11 +204,11 @@ pub fn tile_index(lon: f64, lat: f64, zoom: u8) -> (u32, u32) { (tile.x.min(max_value) as u32, tile.y.min(max_value) as u32) } -pub fn tile_colrow(lng: f64, lat: f64, zoom: u8) -> (u64, u64) { +pub fn tile_colrow(lng: f64, lat: f64, zoom: u8) -> (u32, u32) { let tile_size = EARTH_CIRCUMFERENCE / f64::from(1_u32 << zoom); let (x, y) = wgs84_to_webmercator(lng, lat); - let col = ((x - (EARTH_CIRCUMFERENCE * -0.5)).abs() / tile_size).trunc() as u64; - let row = (((EARTH_CIRCUMFERENCE * 0.5) - y).abs() / tile_size).trunc() as u64; + let col = ((x - (EARTH_CIRCUMFERENCE * -0.5)).abs() / tile_size).trunc() as u32; + let row = (((EARTH_CIRCUMFERENCE * 0.5) - y).abs() / tile_size).trunc() as u32; (col, row) } @@ -228,20 +228,13 @@ pub fn xyz_to_bbox(zoom: u8, min_x: u32, min_y: u32, max_x: u32, max_y: u32) -> /// Convert bounding box to a tile box `(min_x, min_y, max_x, max_y)` for a given zoom #[must_use] -#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] -pub fn bbox_to_xyz(left: f64, bottom: f64, right: f64, top: f64, zoom: u8) -> (u32, u32, u32, u32) { - let (min_x, min_y) = tile_index(left, top, zoom); - let (max_x, max_y) = tile_index(right, bottom, zoom); - (min_x, min_y, max_x, max_y) -} - -pub fn bbox_to_colrow( +pub fn bbox_to_xyz( left: f64, bottom: f64, right: f64, top: f64, zoom: u8, -) -> (u64, u64, u64, u64) { +) -> (u32, u32, u32, u32) { let (min_col, min_row) = tile_colrow(left, top, zoom); let (max_col, max_row) = tile_colrow(right, bottom, zoom); (min_col, min_row, max_col, max_row) @@ -335,7 +328,7 @@ mod tests { assert_relative_eq!(bbox[2], 179.99999999999986, epsilon = f64::EPSILON * 2.0); assert_relative_eq!(bbox[3], 85.05112877980655, epsilon = f64::EPSILON * 2.0); - let xyz = bbox_to_colrow(bbox[0], bbox[1], bbox[2], bbox[3], 0); + let xyz = bbox_to_xyz(bbox[0], bbox[1], bbox[2], bbox[3], 0); assert_eq!(xyz, (0, 0, 0, 0)); let bbox = xyz_to_bbox(1, 0, 0, 0, 0); @@ -348,7 +341,7 @@ mod tests { ); assert_relative_eq!(bbox[3], 85.05112877980655, epsilon = f64::EPSILON * 2.0); - let xyz = bbox_to_colrow(bbox[0], bbox[1], bbox[2], bbox[3], 1); + let xyz = bbox_to_xyz(bbox[0], bbox[1], bbox[2], bbox[3], 1); assert!(xyz.0 == 0 || xyz.0 == 1); assert!(xyz.1 == 0); assert!(xyz.2 == 0 || xyz.2 == 1); @@ -360,7 +353,7 @@ mod tests { assert_relative_eq!(bbox[2], -146.2499999999996, epsilon = f64::EPSILON * 2.0); assert_relative_eq!(bbox[3], 83.979259498862, epsilon = f64::EPSILON * 2.0); - let xyz = bbox_to_colrow(bbox[0], bbox[1], bbox[2], bbox[3], 5); + let xyz = bbox_to_xyz(bbox[0], bbox[1], bbox[2], bbox[3], 5); assert!(xyz.0 == 1 || xyz.0 == 2); assert!(xyz.1 == 0 || xyz.1 == 1); assert!(xyz.2 == 2 || xyz.2 == 3); @@ -372,7 +365,7 @@ mod tests { assert_relative_eq!(bbox[2], -146.2499999999996, epsilon = f64::EPSILON * 2.0); assert_relative_eq!(bbox[3], 81.09321385260832, epsilon = f64::EPSILON * 2.0); - let xyz = bbox_to_colrow(bbox[0], bbox[1], bbox[2], bbox[3], 5); + let xyz = bbox_to_xyz(bbox[0], bbox[1], bbox[2], bbox[3], 5); assert!(xyz.0 == 1 || xyz.0 == 2); assert!(xyz.1 == 2 || xyz.1 == 3); assert!(xyz.2 == 2 || xyz.2 == 3); @@ -382,7 +375,7 @@ mod tests { #[test] fn test_box() { fn tst(left: f64, bottom: f64, right: f64, top: f64, zoom: u8) -> String { - let (x0, y0, x1, y1) = bbox_to_colrow(left, bottom, right, top, zoom); + let (x0, y0, x1, y1) = bbox_to_xyz(left, bottom, right, top, zoom); format!("({x0}, {y0}, {x1}, {y1})") } From ae8b98d61d941ef162ddf022e5ece9b108fcac6a Mon Sep 17 00:00:00 2001 From: sharkAndshark Date: Fri, 15 Dec 2023 17:50:28 +0800 Subject: [PATCH 07/19] fmt and clippy --- martin-tile-utils/src/lib.rs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/martin-tile-utils/src/lib.rs b/martin-tile-utils/src/lib.rs index 2232bddc4..d7681afcd 100644 --- a/martin-tile-utils/src/lib.rs +++ b/martin-tile-utils/src/lib.rs @@ -204,6 +204,7 @@ pub fn tile_index(lon: f64, lat: f64, zoom: u8) -> (u32, u32) { (tile.x.min(max_value) as u32, tile.y.min(max_value) as u32) } +#[allow(clippy::cast_possible_truncation)] pub fn tile_colrow(lng: f64, lat: f64, zoom: u8) -> (u32, u32) { let tile_size = EARTH_CIRCUMFERENCE / f64::from(1_u32 << zoom); let (x, y) = wgs84_to_webmercator(lng, lat); @@ -228,13 +229,7 @@ pub fn xyz_to_bbox(zoom: u8, min_x: u32, min_y: u32, max_x: u32, max_y: u32) -> /// Convert bounding box to a tile box `(min_x, min_y, max_x, max_y)` for a given zoom #[must_use] -pub fn bbox_to_xyz( - left: f64, - bottom: f64, - right: f64, - top: f64, - zoom: u8, -) -> (u32, u32, u32, u32) { +pub fn bbox_to_xyz(left: f64, bottom: f64, right: f64, top: f64, zoom: u8) -> (u32, u32, u32, u32) { let (min_col, min_row) = tile_colrow(left, top, zoom); let (max_col, max_row) = tile_colrow(right, bottom, zoom); (min_col, min_row, max_col, max_row) @@ -261,6 +256,7 @@ pub fn webmercator_to_wgs84(x: f64, y: f64) -> (f64, f64) { (lng, lat) } +#[must_use] pub fn wgs84_to_webmercator(lon: f64, lat: f64) -> (f64, f64) { let x = PI * 6378137.0 * lon / 180.0; let y = ((90.0 + lat) * PI / 360.0).tan().ln() / (PI / 180.0); @@ -275,9 +271,9 @@ mod tests { use std::fs::read; use approx::assert_relative_eq; + use insta::assert_snapshot; use Encoding::{Internal, Uncompressed}; use Format::{Jpeg, Json, Png, Webp}; - use insta::assert_snapshot; use super::*; @@ -378,7 +374,6 @@ mod tests { let (x0, y0, x1, y1) = bbox_to_xyz(left, bottom, right, top, zoom); format!("({x0}, {y0}, {x1}, {y1})") } - assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 0), @"(0, 0, 0, 0)"); assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 1), @"(0, 1, 0, 1)"); assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 2), @"(0, 3, 0, 3)"); @@ -404,7 +399,7 @@ mod tests { assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 22), @"(6553, 3822590, 386662, 4157356)"); assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 23), @"(13107, 7645181, 773324, 8314713)"); assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 24), @"(26214, 15290363, 1546649, 16629427)"); - + // All these are incorrect assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 25), @"(52428, 30580726, 3093299, 33258855)"); assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 26), @"(104857, 61161453, 6186598, 66517711)"); From 56846a881d0e924f1a9b8b1117803c76a508929c Mon Sep 17 00:00:00 2001 From: sharkAndshark Date: Fri, 15 Dec 2023 19:28:50 +0800 Subject: [PATCH 08/19] clippy --- martin-tile-utils/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/martin-tile-utils/src/lib.rs b/martin-tile-utils/src/lib.rs index d7681afcd..c6476a84d 100644 --- a/martin-tile-utils/src/lib.rs +++ b/martin-tile-utils/src/lib.rs @@ -204,6 +204,7 @@ pub fn tile_index(lon: f64, lat: f64, zoom: u8) -> (u32, u32) { (tile.x.min(max_value) as u32, tile.y.min(max_value) as u32) } +#[must_use] #[allow(clippy::cast_possible_truncation)] pub fn tile_colrow(lng: f64, lat: f64, zoom: u8) -> (u32, u32) { let tile_size = EARTH_CIRCUMFERENCE / f64::from(1_u32 << zoom); @@ -258,9 +259,9 @@ pub fn webmercator_to_wgs84(x: f64, y: f64) -> (f64, f64) { #[must_use] pub fn wgs84_to_webmercator(lon: f64, lat: f64) -> (f64, f64) { - let x = PI * 6378137.0 * lon / 180.0; + let x = PI * 6_378_137.0 * lon / 180.0; let y = ((90.0 + lat) * PI / 360.0).tan().ln() / (PI / 180.0); - let y = PI * 6378137.0 * y / 180.0; + let y = PI * 6_378_137.0 * y / 180.0; (x, y) } From 7945f2c22fcfa6fbf98fb25cf9583a9d6ad7a74a Mon Sep 17 00:00:00 2001 From: sharkAndshark Date: Fri, 15 Dec 2023 20:19:10 +0800 Subject: [PATCH 09/19] clippy --- martin-tile-utils/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/martin-tile-utils/src/lib.rs b/martin-tile-utils/src/lib.rs index c6476a84d..0c302e6f7 100644 --- a/martin-tile-utils/src/lib.rs +++ b/martin-tile-utils/src/lib.rs @@ -206,6 +206,7 @@ pub fn tile_index(lon: f64, lat: f64, zoom: u8) -> (u32, u32) { #[must_use] #[allow(clippy::cast_possible_truncation)] +#[allow(clippy::cast_sign_loss)] pub fn tile_colrow(lng: f64, lat: f64, zoom: u8) -> (u32, u32) { let tile_size = EARTH_CIRCUMFERENCE / f64::from(1_u32 << zoom); let (x, y) = wgs84_to_webmercator(lng, lat); From 2dfff7dbe0c3a4c0806d9ab2549924c7b0915d98 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Fri, 15 Dec 2023 22:20:27 -0500 Subject: [PATCH 10/19] Update martin-tile-utils/src/lib.rs --- martin-tile-utils/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/martin-tile-utils/src/lib.rs b/martin-tile-utils/src/lib.rs index 0c302e6f7..5120a00d7 100644 --- a/martin-tile-utils/src/lib.rs +++ b/martin-tile-utils/src/lib.rs @@ -260,7 +260,7 @@ pub fn webmercator_to_wgs84(x: f64, y: f64) -> (f64, f64) { #[must_use] pub fn wgs84_to_webmercator(lon: f64, lat: f64) -> (f64, f64) { - let x = PI * 6_378_137.0 * lon / 180.0; + let x = EARTH_CIRCUMFERENCE / 360.0 * lon; let y = ((90.0 + lat) * PI / 360.0).tan().ln() / (PI / 180.0); let y = PI * 6_378_137.0 * y / 180.0; (x, y) From 1bb848e34402e0aefb3006e9dec5fb75154f0438 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Fri, 15 Dec 2023 22:20:32 -0500 Subject: [PATCH 11/19] Update martin-tile-utils/src/lib.rs --- martin-tile-utils/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/martin-tile-utils/src/lib.rs b/martin-tile-utils/src/lib.rs index 5120a00d7..89067e8c9 100644 --- a/martin-tile-utils/src/lib.rs +++ b/martin-tile-utils/src/lib.rs @@ -262,7 +262,7 @@ pub fn webmercator_to_wgs84(x: f64, y: f64) -> (f64, f64) { pub fn wgs84_to_webmercator(lon: f64, lat: f64) -> (f64, f64) { let x = EARTH_CIRCUMFERENCE / 360.0 * lon; let y = ((90.0 + lat) * PI / 360.0).tan().ln() / (PI / 180.0); - let y = PI * 6_378_137.0 * y / 180.0; + let y = EARTH_CIRCUMFERENCE / 360.0 * y; (x, y) } From 2d69b1a7dc56cb417c4eb80cd4a1642fab1654f5 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Fri, 15 Dec 2023 23:05:57 -0500 Subject: [PATCH 12/19] a few minor fixes --- Cargo.lock | 1 + martin-tile-utils/Cargo.toml | 2 +- martin-tile-utils/src/lib.rs | 9 +++------ 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2218bb5a0..a60a38fd3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1904,6 +1904,7 @@ name = "martin-tile-utils" version = "0.2.0" dependencies = [ "approx", + "insta", "tile-grid", ] diff --git a/martin-tile-utils/Cargo.toml b/martin-tile-utils/Cargo.toml index 8b55fe125..35c7c160e 100644 --- a/martin-tile-utils/Cargo.toml +++ b/martin-tile-utils/Cargo.toml @@ -21,4 +21,4 @@ tile-grid.workspace = true [dev-dependencies] approx.workspace = true -insta = { workspace = true, features = ["toml", "yaml"] } +insta.workspace = true diff --git a/martin-tile-utils/src/lib.rs b/martin-tile-utils/src/lib.rs index 89067e8c9..8631db1a9 100644 --- a/martin-tile-utils/src/lib.rs +++ b/martin-tile-utils/src/lib.rs @@ -210,8 +210,8 @@ pub fn tile_index(lon: f64, lat: f64, zoom: u8) -> (u32, u32) { pub fn tile_colrow(lng: f64, lat: f64, zoom: u8) -> (u32, u32) { let tile_size = EARTH_CIRCUMFERENCE / f64::from(1_u32 << zoom); let (x, y) = wgs84_to_webmercator(lng, lat); - let col = ((x - (EARTH_CIRCUMFERENCE * -0.5)).abs() / tile_size).trunc() as u32; - let row = (((EARTH_CIRCUMFERENCE * 0.5) - y).abs() / tile_size).trunc() as u32; + let col = (((x - (EARTH_CIRCUMFERENCE * -0.5)).abs() / tile_size) as u32).min((1 << zoom) - 1); + let row = ((((EARTH_CIRCUMFERENCE * 0.5) - y).abs() / tile_size) as u32).min((1 << zoom) - 1); (col, row) } @@ -261,8 +261,7 @@ pub fn webmercator_to_wgs84(x: f64, y: f64) -> (f64, f64) { #[must_use] pub fn wgs84_to_webmercator(lon: f64, lat: f64) -> (f64, f64) { let x = EARTH_CIRCUMFERENCE / 360.0 * lon; - let y = ((90.0 + lat) * PI / 360.0).tan().ln() / (PI / 180.0); - let y = EARTH_CIRCUMFERENCE / 360.0 * y; + let y = EARTH_CIRCUMFERENCE / 360.0 * (((90.0 + lat) * PI / 360.0).tan().ln() / (PI / 180.0)); (x, y) } @@ -401,8 +400,6 @@ mod tests { assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 22), @"(6553, 3822590, 386662, 4157356)"); assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 23), @"(13107, 7645181, 773324, 8314713)"); assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 24), @"(26214, 15290363, 1546649, 16629427)"); - - // All these are incorrect assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 25), @"(52428, 30580726, 3093299, 33258855)"); assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 26), @"(104857, 61161453, 6186598, 66517711)"); assert_snapshot!(tst(-179.43749999999955,-84.76987877980656,-146.8124999999996,-81.37446385260833, 27), @"(209715, 122322907, 12373196, 133035423)"); From 27196264c907c6ee8c39fb040912cc2cad545c4d Mon Sep 17 00:00:00 2001 From: sharkAndshark Date: Sun, 17 Dec 2023 17:36:22 +0800 Subject: [PATCH 13/19] Remove tile_index --- martin-tile-utils/src/lib.rs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/martin-tile-utils/src/lib.rs b/martin-tile-utils/src/lib.rs index 8631db1a9..b9f299c31 100644 --- a/martin-tile-utils/src/lib.rs +++ b/martin-tile-utils/src/lib.rs @@ -195,15 +195,6 @@ impl Display for TileInfo { } /// Convert longitude and latitude to a tile (x,y) coordinates for a given zoom -#[must_use] -#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] -pub fn tile_index(lon: f64, lat: f64, zoom: u8) -> (u32, u32) { - assert!(zoom <= MAX_ZOOM, "zoom {zoom} must be <= {MAX_ZOOM}"); - let tile = web_merc().tile(lon, lat, zoom).unwrap(); - let max_value = (1_u64 << zoom) - 1; - (tile.x.min(max_value) as u32, tile.y.min(max_value) as u32) -} - #[must_use] #[allow(clippy::cast_possible_truncation)] #[allow(clippy::cast_sign_loss)] @@ -312,8 +303,8 @@ mod tests { } #[test] - fn test_tile_index() { - assert_eq!((0, 0), tile_index(-180.0, 85.0511, 0)); + fn test_tile_colrow() { + assert_eq!((0, 0), tile_colrow(-180.0, 85.0511, 0)); } #[test] From 0fd5e164f414e43e88d5458219d0b4436e442b59 Mon Sep 17 00:00:00 2001 From: sharkAndshark Date: Sun, 17 Dec 2023 17:41:11 +0800 Subject: [PATCH 14/19] Minior imrovement to tile_colrow function --- martin-tile-utils/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/martin-tile-utils/src/lib.rs b/martin-tile-utils/src/lib.rs index b9f299c31..a3e3afa3d 100644 --- a/martin-tile-utils/src/lib.rs +++ b/martin-tile-utils/src/lib.rs @@ -203,7 +203,9 @@ pub fn tile_colrow(lng: f64, lat: f64, zoom: u8) -> (u32, u32) { let (x, y) = wgs84_to_webmercator(lng, lat); let col = (((x - (EARTH_CIRCUMFERENCE * -0.5)).abs() / tile_size) as u32).min((1 << zoom) - 1); let row = ((((EARTH_CIRCUMFERENCE * 0.5) - y).abs() / tile_size) as u32).min((1 << zoom) - 1); - (col, row) + + let max_value = (1_u32 << zoom) - 1; + (col.min(max_value), row.min(max_value)) } /// Convert min/max XYZ tile coordinates to a bounding box values. From 4bc205b23b9538a4f587fa6f81d6bc257ff931a0 Mon Sep 17 00:00:00 2001 From: sharkAndshark Date: Sun, 17 Dec 2023 19:21:23 +0800 Subject: [PATCH 15/19] remove tile-grid --- martin-tile-utils/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/martin-tile-utils/Cargo.toml b/martin-tile-utils/Cargo.toml index 35c7c160e..63eca37c3 100644 --- a/martin-tile-utils/Cargo.toml +++ b/martin-tile-utils/Cargo.toml @@ -17,7 +17,6 @@ repository.workspace = true rust-version.workspace = true [dependencies] -tile-grid.workspace = true [dev-dependencies] approx.workspace = true From 8bde9038ff2815ce426c38fe89d6e0b2091b0f25 Mon Sep 17 00:00:00 2001 From: sharkAndshark Date: Sun, 17 Dec 2023 20:53:52 +0800 Subject: [PATCH 16/19] Remove tile-grid, udpate mercator and udpate test --- martin-tile-utils/src/lib.rs | 105 +++++++++++++++-------------------- 1 file changed, 44 insertions(+), 61 deletions(-) diff --git a/martin-tile-utils/src/lib.rs b/martin-tile-utils/src/lib.rs index a3e3afa3d..776c3a7bf 100644 --- a/martin-tile-utils/src/lib.rs +++ b/martin-tile-utils/src/lib.rs @@ -6,18 +6,10 @@ use std::f64::consts::PI; use std::fmt::Display; -use tile_grid::{tms, Tms, Xyz}; - pub const EARTH_CIRCUMFERENCE: f64 = 40_075_016.685_578_5; pub const EARTH_RADIUS: f64 = EARTH_CIRCUMFERENCE / 2.0 / PI; pub const MAX_ZOOM: u8 = 30; -use std::sync::OnceLock; - -fn web_merc() -> &'static Tms { - static TMS: OnceLock = OnceLock::new(); - TMS.get_or_init(|| tms().lookup("WebMercatorQuad").unwrap()) -} #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Format { @@ -203,25 +195,33 @@ pub fn tile_colrow(lng: f64, lat: f64, zoom: u8) -> (u32, u32) { let (x, y) = wgs84_to_webmercator(lng, lat); let col = (((x - (EARTH_CIRCUMFERENCE * -0.5)).abs() / tile_size) as u32).min((1 << zoom) - 1); let row = ((((EARTH_CIRCUMFERENCE * 0.5) - y).abs() / tile_size) as u32).min((1 << zoom) - 1); - - let max_value = (1_u32 << zoom) - 1; - (col.min(max_value), row.min(max_value)) + (col, row) } /// Convert min/max XYZ tile coordinates to a bounding box values. /// The result is `[min_lng, min_lat, max_lng, max_lat]` #[must_use] -pub fn xyz_to_bbox(zoom: u8, min_x: u32, min_y: u32, max_x: u32, max_y: u32) -> [f64; 4] { +pub fn xyz_to_bbox(zoom: u8, min_col: u32, min_row: u32, max_col: u32, max_row: u32) -> [f64; 4] { assert!(zoom <= MAX_ZOOM, "zoom {zoom} must be <= {MAX_ZOOM}"); - let left_top_bounds = web_merc().xy_bounds(&Xyz::new(u64::from(min_x), u64::from(min_y), zoom)); - let right_bottom_bounds = - web_merc().xy_bounds(&Xyz::new(u64::from(max_x), u64::from(max_y), zoom)); - let (min_lng, min_lat) = webmercator_to_wgs84(left_top_bounds.left, right_bottom_bounds.bottom); - let (max_lng, max_lat) = webmercator_to_wgs84(right_bottom_bounds.right, left_top_bounds.top); + let tile_length = EARTH_CIRCUMFERENCE / f64::from(1_u32 << zoom); + + let left_down_bbox = tile_bbox(min_col, max_row, tile_length); + let right_top_bbox = tile_bbox(max_col, min_row, tile_length); + + let (min_lng, min_lat) = webmercator_to_wgs84(left_down_bbox[0], left_down_bbox[1]); + let (max_lng, max_lat) = webmercator_to_wgs84(right_top_bbox[2], right_top_bbox[3]); [min_lng, min_lat, max_lng, max_lat] } +#[allow(clippy::cast_lossless)] +fn tile_bbox(x: u32, y: u32, tile_length: f64) -> [f64; 4] { + let min_x = EARTH_CIRCUMFERENCE * -0.5 + x as f64 * tile_length; + let max_y = EARTH_CIRCUMFERENCE * 0.5 - y as f64 * tile_length; + + [min_x, max_y - tile_length, min_x + tile_length, max_y] +} + /// Convert bounding box to a tile box `(min_x, min_y, max_x, max_y)` for a given zoom #[must_use] pub fn bbox_to_xyz(left: f64, bottom: f64, right: f64, top: f64, zoom: u8) -> (u32, u32, u32, u32) { @@ -253,9 +253,17 @@ pub fn webmercator_to_wgs84(x: f64, y: f64) -> (f64, f64) { #[must_use] pub fn wgs84_to_webmercator(lon: f64, lat: f64) -> (f64, f64) { - let x = EARTH_CIRCUMFERENCE / 360.0 * lon; - let y = EARTH_CIRCUMFERENCE / 360.0 * (((90.0 + lat) * PI / 360.0).tan().ln() / (PI / 180.0)); - (x, y) + (to_mercator_x(lon), to_mercator_y(lat)) +} + +fn to_mercator_y(lat: f64) -> f64 { + let rad = lat * PI / 180.0; + let sin = rad.sin(); + EARTH_RADIUS / 2.0 * ((1.0 + sin) / (1.0 - sin)).ln() +} + +fn to_mercator_x(lon: f64) -> f64 { + lon * PI / 180.0 * EARTH_RADIUS } #[cfg(test)] @@ -313,57 +321,32 @@ mod tests { fn test_xyz_to_bbox() { // you could easily get test cases from maptiler: https://www.maptiler.com/google-maps-coordinates-tile-bounds-projection/#4/-118.82/71.02 let bbox = xyz_to_bbox(0, 0, 0, 0, 0); - assert_relative_eq!(bbox[0], -179.99999999999955, epsilon = f64::EPSILON * 2.0); + assert_relative_eq!(bbox[0], -180.0, epsilon = f64::EPSILON * 2.0); assert_relative_eq!(bbox[1], -85.0511287798066, epsilon = f64::EPSILON * 2.0); - assert_relative_eq!(bbox[2], 179.99999999999986, epsilon = f64::EPSILON * 2.0); - assert_relative_eq!(bbox[3], 85.05112877980655, epsilon = f64::EPSILON * 2.0); - - let xyz = bbox_to_xyz(bbox[0], bbox[1], bbox[2], bbox[3], 0); - assert_eq!(xyz, (0, 0, 0, 0)); + assert_relative_eq!(bbox[2], 180.0, epsilon = f64::EPSILON * 2.0); + assert_relative_eq!(bbox[3], 85.0511287798066, epsilon = f64::EPSILON * 2.0); let bbox = xyz_to_bbox(1, 0, 0, 0, 0); - assert_relative_eq!(bbox[0], -179.99999999999955, epsilon = f64::EPSILON * 2.0); - assert_relative_eq!(bbox[1], 2.007891127734306e-13, epsilon = f64::EPSILON * 2.0); - assert_relative_eq!( - bbox[2], - -2.007891127734306e-13, - epsilon = f64::EPSILON * 2.0 - ); - assert_relative_eq!(bbox[3], 85.05112877980655, epsilon = f64::EPSILON * 2.0); - - let xyz = bbox_to_xyz(bbox[0], bbox[1], bbox[2], bbox[3], 1); - assert!(xyz.0 == 0 || xyz.0 == 1); - assert!(xyz.1 == 0); - assert!(xyz.2 == 0 || xyz.2 == 1); - assert!(xyz.3 == 0 || xyz.3 == 1); + assert_relative_eq!(bbox[0], -180.0, epsilon = f64::EPSILON * 2.0); + assert_relative_eq!(bbox[1], 0.0, epsilon = f64::EPSILON * 2.0); + assert_relative_eq!(bbox[2], 0.0, epsilon = f64::EPSILON * 2.0); + assert_relative_eq!(bbox[3], 85.0511287798066, epsilon = f64::EPSILON * 2.0); let bbox = xyz_to_bbox(5, 1, 1, 2, 2); - assert_relative_eq!(bbox[0], -168.74999999999955, epsilon = f64::EPSILON * 2.0); - assert_relative_eq!(bbox[1], 81.09321385260832, epsilon = f64::EPSILON * 2.0); - assert_relative_eq!(bbox[2], -146.2499999999996, epsilon = f64::EPSILON * 2.0); - assert_relative_eq!(bbox[3], 83.979259498862, epsilon = f64::EPSILON * 2.0); - - let xyz = bbox_to_xyz(bbox[0], bbox[1], bbox[2], bbox[3], 5); - assert!(xyz.0 == 1 || xyz.0 == 2); - assert!(xyz.1 == 0 || xyz.1 == 1); - assert!(xyz.2 == 2 || xyz.2 == 3); - assert!(xyz.3 == 2 || xyz.3 == 3); + assert_relative_eq!(bbox[0], -168.75, epsilon = f64::EPSILON * 2.0); + assert_relative_eq!(bbox[1], 81.09321385260837, epsilon = f64::EPSILON * 2.0); + assert_relative_eq!(bbox[2], -146.25, epsilon = f64::EPSILON * 2.0); + assert_relative_eq!(bbox[3], 83.97925949886205, epsilon = f64::EPSILON * 2.0); let bbox = xyz_to_bbox(5, 1, 3, 2, 5); - assert_relative_eq!(bbox[0], -168.74999999999955, epsilon = f64::EPSILON * 2.0); - assert_relative_eq!(bbox[1], 74.01954331150218, epsilon = f64::EPSILON * 2.0); - assert_relative_eq!(bbox[2], -146.2499999999996, epsilon = f64::EPSILON * 2.0); - assert_relative_eq!(bbox[3], 81.09321385260832, epsilon = f64::EPSILON * 2.0); - - let xyz = bbox_to_xyz(bbox[0], bbox[1], bbox[2], bbox[3], 5); - assert!(xyz.0 == 1 || xyz.0 == 2); - assert!(xyz.1 == 2 || xyz.1 == 3); - assert!(xyz.2 == 2 || xyz.2 == 3); - assert!(xyz.3 == 5 || xyz.3 == 6); + assert_relative_eq!(bbox[0], -168.75, epsilon = f64::EPSILON * 2.0); + assert_relative_eq!(bbox[1], 74.01954331150226, epsilon = f64::EPSILON * 2.0); + assert_relative_eq!(bbox[2], -146.25, epsilon = f64::EPSILON * 2.0); + assert_relative_eq!(bbox[3], 81.09321385260837, epsilon = f64::EPSILON * 2.0); } #[test] - fn test_box() { + fn test_box_to_xyz() { fn tst(left: f64, bottom: f64, right: f64, top: f64, zoom: u8) -> String { let (x0, y0, x1, y1) = bbox_to_xyz(left, bottom, right, top, zoom); format!("({x0}, {y0}, {x1}, {y1})") From 8f9c61915bc823f9c231c458c28aca47045e112c Mon Sep 17 00:00:00 2001 From: sharkAndshark Date: Sun, 17 Dec 2023 20:57:43 +0800 Subject: [PATCH 17/19] Add comment --- martin-tile-utils/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/martin-tile-utils/src/lib.rs b/martin-tile-utils/src/lib.rs index 776c3a7bf..53aafd4ac 100644 --- a/martin-tile-utils/src/lib.rs +++ b/martin-tile-utils/src/lib.rs @@ -251,6 +251,8 @@ pub fn webmercator_to_wgs84(x: f64, y: f64) -> (f64, f64) { (lng, lat) } +/// transform WGS84 to WebMercator +// from https://github.com/Esri/arcgis-osm-editor/blob/e4b9905c264aa22f8eeb657efd52b12cdebea69a/src/OSMWeb10_1/Utils/WebMercator.cs #[must_use] pub fn wgs84_to_webmercator(lon: f64, lat: f64) -> (f64, f64) { (to_mercator_x(lon), to_mercator_y(lat)) From 93d9f278da995e1d264bbcec18a6fcd7d96043dc Mon Sep 17 00:00:00 2001 From: sharkAndshark Date: Mon, 18 Dec 2023 09:43:07 +0800 Subject: [PATCH 18/19] Rename arguments and remove tiny functions --- martin-tile-utils/src/lib.rs | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/martin-tile-utils/src/lib.rs b/martin-tile-utils/src/lib.rs index 53aafd4ac..5e7aa4f0f 100644 --- a/martin-tile-utils/src/lib.rs +++ b/martin-tile-utils/src/lib.rs @@ -190,7 +190,7 @@ impl Display for TileInfo { #[must_use] #[allow(clippy::cast_possible_truncation)] #[allow(clippy::cast_sign_loss)] -pub fn tile_colrow(lng: f64, lat: f64, zoom: u8) -> (u32, u32) { +pub fn tile_index(lng: f64, lat: f64, zoom: u8) -> (u32, u32) { let tile_size = EARTH_CIRCUMFERENCE / f64::from(1_u32 << zoom); let (x, y) = wgs84_to_webmercator(lng, lat); let col = (((x - (EARTH_CIRCUMFERENCE * -0.5)).abs() / tile_size) as u32).min((1 << zoom) - 1); @@ -201,13 +201,13 @@ pub fn tile_colrow(lng: f64, lat: f64, zoom: u8) -> (u32, u32) { /// Convert min/max XYZ tile coordinates to a bounding box values. /// The result is `[min_lng, min_lat, max_lng, max_lat]` #[must_use] -pub fn xyz_to_bbox(zoom: u8, min_col: u32, min_row: u32, max_col: u32, max_row: u32) -> [f64; 4] { +pub fn xyz_to_bbox(zoom: u8, min_x: u32, min_y: u32, max_x: u32, max_y: u32) -> [f64; 4] { assert!(zoom <= MAX_ZOOM, "zoom {zoom} must be <= {MAX_ZOOM}"); let tile_length = EARTH_CIRCUMFERENCE / f64::from(1_u32 << zoom); - let left_down_bbox = tile_bbox(min_col, max_row, tile_length); - let right_top_bbox = tile_bbox(max_col, min_row, tile_length); + let left_down_bbox = tile_bbox(min_x, max_y, tile_length); + let right_top_bbox = tile_bbox(max_x, min_y, tile_length); let (min_lng, min_lat) = webmercator_to_wgs84(left_down_bbox[0], left_down_bbox[1]); let (max_lng, max_lat) = webmercator_to_wgs84(right_top_bbox[2], right_top_bbox[3]); @@ -225,8 +225,8 @@ fn tile_bbox(x: u32, y: u32, tile_length: f64) -> [f64; 4] { /// Convert bounding box to a tile box `(min_x, min_y, max_x, max_y)` for a given zoom #[must_use] pub fn bbox_to_xyz(left: f64, bottom: f64, right: f64, top: f64, zoom: u8) -> (u32, u32, u32, u32) { - let (min_col, min_row) = tile_colrow(left, top, zoom); - let (max_col, max_row) = tile_colrow(right, bottom, zoom); + let (min_col, min_row) = tile_index(left, top, zoom); + let (max_col, max_row) = tile_index(right, bottom, zoom); (min_col, min_row, max_col, max_row) } @@ -251,21 +251,17 @@ pub fn webmercator_to_wgs84(x: f64, y: f64) -> (f64, f64) { (lng, lat) } -/// transform WGS84 to WebMercator +/// transform WGS84 to `WebMercator` // from https://github.com/Esri/arcgis-osm-editor/blob/e4b9905c264aa22f8eeb657efd52b12cdebea69a/src/OSMWeb10_1/Utils/WebMercator.cs #[must_use] pub fn wgs84_to_webmercator(lon: f64, lat: f64) -> (f64, f64) { - (to_mercator_x(lon), to_mercator_y(lat)) -} + let x = lon * PI / 180.0 * EARTH_RADIUS; -fn to_mercator_y(lat: f64) -> f64 { let rad = lat * PI / 180.0; let sin = rad.sin(); - EARTH_RADIUS / 2.0 * ((1.0 + sin) / (1.0 - sin)).ln() -} + let y = EARTH_RADIUS / 2.0 * ((1.0 + sin) / (1.0 - sin)).ln(); -fn to_mercator_x(lon: f64) -> f64 { - lon * PI / 180.0 * EARTH_RADIUS + (x, y) } #[cfg(test)] @@ -316,7 +312,7 @@ mod tests { #[test] fn test_tile_colrow() { - assert_eq!((0, 0), tile_colrow(-180.0, 85.0511, 0)); + assert_eq!((0, 0), tile_index(-180.0, 85.0511, 0)); } #[test] From a83ccd76570a35b1ebc863da019c3c37cc634abc Mon Sep 17 00:00:00 2001 From: sharkAndshark Date: Mon, 18 Dec 2023 09:53:31 +0800 Subject: [PATCH 19/19] Update test results --- mbtiles/src/summary.rs | 64 +++++++++---------- .../martin-cp/flat-with-hash_summary.txt | 2 +- tests/expected/martin-cp/flat_summary.txt | 4 +- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/mbtiles/src/summary.rs b/mbtiles/src/summary.rs index b7eb474da..095a194a7 100644 --- a/mbtiles/src/summary.rs +++ b/mbtiles/src/summary.rs @@ -239,10 +239,10 @@ mod tests { max_tile_size: 1107 avg_tile_size: 96.2295918367347 bbox: - - -179.99999999999955 - - -85.05112877980659 - - 180.00000000000028 - - 85.05112877980655 + - -180 + - -85.0511287798066 + - 180.00000000000003 + - 85.0511287798066 min_zoom: 0 max_zoom: 6 zoom_info: @@ -252,70 +252,70 @@ mod tests { max_tile_size: 1107 avg_tile_size: 1107 bbox: - - -179.99999999999955 - - -85.05112877980659 - - 179.99999999999986 - - 85.05112877980655 + - -180 + - -85.0511287798066 + - 180 + - 85.0511287798066 - zoom: 1 tile_count: 4 min_tile_size: 160 max_tile_size: 650 avg_tile_size: 366.5 bbox: - - -179.99999999999955 - - -85.05112877980652 - - 179.99999999999915 - - 85.05112877980655 + - -180 + - -85.0511287798066 + - 180 + - 85.0511287798066 - zoom: 2 tile_count: 7 min_tile_size: 137 max_tile_size: 495 avg_tile_size: 239.57142857142858 bbox: - - -179.99999999999955 - - -66.51326044311165 - - 179.99999999999915 - - 66.51326044311182 + - -180 + - -66.51326044311186 + - 180.00000000000003 + - 66.51326044311186 - zoom: 3 tile_count: 17 min_tile_size: 67 max_tile_size: 246 avg_tile_size: 134 bbox: - - -134.99999999999957 - - -40.979898069620376 - - 180.00000000000028 - - 66.51326044311169 + - -135 + - -40.97989806962013 + - 179.99999999999997 + - 66.51326044311186 - zoom: 4 tile_count: 38 min_tile_size: 64 max_tile_size: 175 avg_tile_size: 86 bbox: - - -134.99999999999963 - - -40.979898069620106 - - 179.99999999999966 - - 66.51326044311175 + - -135 + - -40.97989806962014 + - 180.00000000000003 + - 66.51326044311186 - zoom: 5 tile_count: 57 min_tile_size: 64 max_tile_size: 107 avg_tile_size: 72.7719298245614 bbox: - - -123.74999999999966 - - -40.979898069620106 - - 179.99999999999966 - - 61.606396371386154 + - -123.75000000000001 + - -40.97989806962013 + - 179.99999999999997 + - 61.60639637138628 - zoom: 6 tile_count: 72 min_tile_size: 64 max_tile_size: 97 avg_tile_size: 68.29166666666667 bbox: - - -123.74999999999957 - - -40.979898069620305 - - 180.00000000000009 - - 61.606396371386104 + - -123.75000000000001 + - -40.97989806962015 + - 180.00000000000003 + - 61.60639637138628 "###); Ok(()) diff --git a/tests/expected/martin-cp/flat-with-hash_summary.txt b/tests/expected/martin-cp/flat-with-hash_summary.txt index 25b81ef4d..fedde3215 100644 --- a/tests/expected/martin-cp/flat-with-hash_summary.txt +++ b/tests/expected/martin-cp/flat-with-hash_summary.txt @@ -7,7 +7,7 @@ Page size: 512B 1 | 4 | 474B | 983B | 609B | -180,-85,180,85 2 | 5 | 150B | 865B | 451B | -90,-67,180,67 3 | 8 | 57B | 839B | 264B | -45,-41,180,67 - 4 | 13 | 57B | 751B | 216B | -22,-22,157,56 + 4 | 13 | 57B | 751B | 216B | -23,-22,158,56 5 | 27 | 57B | 666B | 167B | -11,-11,146,49 6 | 69 | 57B | 636B | 127B | -6,-6,146,45 all | 127 | 57B | 983B | 187B | -180,-85,180,85 diff --git a/tests/expected/martin-cp/flat_summary.txt b/tests/expected/martin-cp/flat_summary.txt index 538d464ef..992a63bbb 100644 --- a/tests/expected/martin-cp/flat_summary.txt +++ b/tests/expected/martin-cp/flat_summary.txt @@ -4,10 +4,10 @@ Page size: 512B Zoom | Count | Smallest | Largest | Average | Bounding Box 0 | 1 | 643B | 643B | 643B | -180,-85,180,85 - 1 | 2 | 150B | 172B | 161B | -180,-85,-0,85 + 1 | 2 | 150B | 172B | 161B | -180,-85,0,85 2 | 4 | 291B | 690B | 414B | -90,-67,90,67 3 | 7 | 75B | 727B | 263B | -45,-41,90,67 - 4 | 13 | 75B | 684B | 225B | -22,-22,157,56 + 4 | 13 | 75B | 684B | 225B | -23,-22,158,56 5 | 27 | 75B | 659B | 195B | -11,-11,146,49 6 | 69 | 75B | 633B | 155B | -6,-6,146,45 all | 123 | 75B | 727B | 190B | -180,-85,180,85