1use crate::{tile::Xyz, tms::Tms};
2use ogcapi_types::tiles::TileMatrix;
3
4fn is_power_of_two(number: u64) -> bool {
6 number & number.saturating_sub(1) == 0 && number != 0
7}
8
9pub(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 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 (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 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}