tile_grid/
quadkey.rs

1use crate::{tile::Xyz, tms::Tms};
2use ogcapi_types::tiles::TileMatrix;
3
4/// Check if a number is a power of 2
5fn is_power_of_two(number: u64) -> bool {
6    number & number.saturating_sub(1) == 0 && number != 0
7}
8
9/// Check if a Tile Matrix Set supports quadkeys
10pub(crate) fn check_quadkey_support(tms: &[TileMatrix]) -> bool {
11    tms.iter().enumerate().take(tms.len() - 1).all(|(i, t)| {
12        t.matrix_width == t.matrix_height
13            && is_power_of_two(t.matrix_width.into())
14            && (u64::from(t.matrix_width) * 2) == u64::from(tms[i + 1].matrix_width)
15    })
16}
17
18impl Tms {
19    /// Get the quadkey of a tile
20    ///
21    /// # Arguments
22    /// * `tile` : instance of Tile
23    pub fn quadkey(&self, tile: &Xyz) -> String {
24        if !self.is_quadtree {
25            panic!("This Tile Matrix Set doesn't support 2 x 2 quadkeys.");
26        }
27
28        let t = tile;
29        let mut qk = vec![];
30        // for z in range(t.z, self.minzoom, -1)
31        for z in (self.minzoom() + 1..=t.z).rev() {
32            let mut digit = 0;
33            let mask = 1 << (z - 1);
34            if t.x & mask != 0 {
35                digit += 1;
36            }
37            if t.y & mask != 0 {
38                digit += 2;
39            }
40            qk.push(digit.to_string());
41        }
42
43        qk.join("")
44    }
45
46    /// Get the tile corresponding to a quadkey
47    ///
48    /// # Arguments
49    /// * `qk` - A quadkey string.
50    pub fn quadkey_to_tile(&self, qk: &str) -> Xyz {
51        if !self.is_quadtree {
52            panic!("This Tile Matrix Set doesn't support 2 x 2 quadkeys.");
53        }
54
55        if qk.is_empty() {
56            return Xyz::new(0, 0, 0);
57        }
58
59        let mut xtile = 0;
60        let mut ytile = 0;
61        let mut z = 0;
62        for (i, digit) in qk.chars().rev().enumerate() {
63            z = i as u8;
64            let mask = 1 << i;
65            if digit == '1' {
66                xtile |= mask;
67            } else if digit == '2' {
68                ytile |= mask;
69            } else if digit == '3' {
70                xtile |= mask;
71                ytile |= mask;
72            } else if digit != '0' {
73                panic!("Unexpected quadkey digit: {}", digit);
74            }
75        }
76
77        Xyz::new(xtile, ytile, z + 1)
78    }
79}