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}