utiles_core/quadkey.rs
1//! Quadkey conversion util(e)ities.
2use crate::errors::{UtilesCoreError, UtilesCoreResult};
3use crate::Tile;
4
5/// Return the quadkey for a tile as a vector of u8 values (0, 1, 2, 3).
6#[must_use]
7pub fn xyz2quadkey_vec(x: u32, y: u32, z: u8) -> Vec<u8> {
8 let mut qk_arr = Vec::with_capacity(z as usize);
9 // let mut quadkey = String::new();
10 for i in (0..z).rev() {
11 let mut digit: u8 = 0;
12 let mask = 1 << i;
13 if (x & mask) != 0 {
14 digit += 1;
15 }
16 if (y & mask) != 0 {
17 digit += 2;
18 }
19 qk_arr.push(digit);
20 }
21 qk_arr
22}
23
24/// Return the quadkey for a tile as a string.
25/// # Examples
26/// ```
27/// use utiles_core::xyz2quadkey;
28/// let quadkey = xyz2quadkey(486, 332, 10);
29/// assert_eq!(quadkey, "0313102310");
30/// ```
31#[must_use]
32pub fn xyz2quadkey(x: u32, y: u32, z: u8) -> String {
33 xyz2quadkey_vec(x, y, z)
34 .iter()
35 .map(|&c| (c + b'0') as char)
36 .collect()
37}
38
39/// Return (x, y, z) for a quadkey as a tuple.
40///
41/// # Errors
42///
43/// Returns an error if the quadkey is invalid and cannot be converted to
44/// tile xyz.
45///
46/// # Examples
47/// ```
48/// use utiles_core::quadkey2xyz;
49/// let one_two_three = quadkey2xyz("123").unwrap();
50/// assert_eq!(one_two_three, (5, 3, 3));
51/// let xyz = quadkey2xyz("0313102310").unwrap();
52/// assert_eq!(xyz, (486, 332, 10));
53/// ```
54pub fn quadkey2xyz(quadkey: &str) -> UtilesCoreResult<(u32, u32, u8)> {
55 // Version with fold:
56 // quadkey.chars().try_fold((0, 0, 0), |(mut x, mut y, z), c| {
57 // x <<= 1;
58 // y <<= 1;
59 //
60 // match c {
61 // '0' => Ok((x, y, z + 1)),
62 // '1' => Ok((x | 1, y, z + 1)),
63 // '2' => Ok((x, y | 1, z + 1)),
64 // '3' => Ok((x | 1, y | 1, z + 1)),
65 // _ => Err(UtilesError::InvalidQuadkey(c.to_string())),
66 // }
67 // })
68 let mut x = 0;
69 let mut y = 0;
70 let mut z = 0;
71 for c in quadkey.chars() {
72 x <<= 1;
73 y <<= 1;
74 z += 1;
75 match c {
76 '0' => {}
77 '1' => {
78 x += 1;
79 }
80 '2' => {
81 y += 1;
82 }
83 '3' => {
84 x += 1;
85 y += 1;
86 }
87 _ => {
88 return Err(UtilesCoreError::InvalidQuadkey(c.to_string()));
89 }
90 }
91 }
92 Ok((x, y, z))
93}
94
95/// Return Tile struct from quadkey string
96///
97/// # Errors
98///
99/// Returns an error if the quadkey is invalid and cannot be converted to
100/// tile xyz.
101///
102/// # Examples
103/// ```
104/// use utiles_core::{Tile, quadkey2tile};
105/// let tile = quadkey2tile("0313102310").unwrap();
106/// assert_eq!(tile, Tile::new(486, 332, 10));
107/// ```
108pub fn quadkey2tile(quadkey: &str) -> UtilesCoreResult<Tile> {
109 let xyz = quadkey2xyz(quadkey)?;
110 Ok(Tile::new(xyz.0, xyz.1, xyz.2))
111}
112
113/// Return y-flipped quadkey
114#[must_use]
115pub fn quadkey_flipy(quadkey: &str) -> String {
116 let mut quadkey_flipped = String::new();
117 for c in quadkey.chars() {
118 quadkey_flipped.push(match c {
119 '0' => '2',
120 '1' => '3',
121 '2' => '0',
122 '3' => '1',
123 _ => return String::new(),
124 });
125 }
126 quadkey_flipped
127}