utiles_core/pmtiles/
pmtile_id.rs

1use crate::int_2_offset_zoom;
2
3/// Convert x,y,z to pmtile-id.
4#[must_use]
5pub fn xyz2pmid(x: u32, y: u32, z: u8) -> u64 {
6    if z == 0 {
7        return 0;
8    }
9    let base_id: u64 = (4u64.pow(u32::from(z)) - 1) / 3;
10    let h = fast_hilbert::xy2h(x, y, z);
11    base_id + h
12}
13
14/// Convert z,x,y to pmtile-id.
15#[allow(dead_code)]
16#[must_use]
17pub fn zxy2pmid(z: u8, x: u32, y: u32) -> u64 {
18    xyz2pmid(x, y, z)
19}
20
21/// Convert pmtile-id to (x, y, z).
22#[must_use]
23pub fn pmid2xyz(i: u64) -> (u32, u32, u8) {
24    if i == 0 {
25        return (0, 0, 0);
26    }
27    let (i_o, z) = int_2_offset_zoom(i);
28    let (x, y) = fast_hilbert::h2xy(i_o, z);
29    (x, y, z)
30}
31
32/// Convert pmtile-id to (z, x, y).
33#[allow(dead_code)]
34#[must_use]
35pub fn pmid2zxy(i: u64) -> (u8, u32, u32) {
36    let (x, y, z) = pmid2xyz(i);
37    (z, x, y)
38}
39
40/// Fast parent ID calculation without converting to ZXY (ported from pmtiles go)
41#[must_use]
42pub fn parent_id(i: u64) -> u64 {
43    let mut acc: u64 = 0;
44    let mut last_acc: u64 = 0;
45    let mut z: u8 = 0;
46    loop {
47        let num_tiles: u64 = (1 << z) * (1 << z);
48        if acc + num_tiles > i {
49            return last_acc + (i - acc) / 4;
50        }
51        last_acc = acc;
52        acc += num_tiles;
53        z += 1;
54    }
55}
56
57// Tests ported from pmtiles go with the help of good old sed and 10 mins of checking it by hand!
58#[cfg(test)]
59mod tests {
60    use super::*;
61
62    #[test]
63    fn test_zxy_to_id() {
64        assert_eq!(0, zxy2pmid(0, 0, 0));
65        assert_eq!(1, zxy2pmid(1, 0, 0));
66        assert_eq!(2, zxy2pmid(1, 0, 1));
67        assert_eq!(3, zxy2pmid(1, 1, 1));
68        assert_eq!(4, zxy2pmid(1, 1, 0));
69        assert_eq!(5, zxy2pmid(2, 0, 0));
70    }
71
72    #[test]
73    fn test_id_to_zxy() {
74        let (z, x, y) = pmid2zxy(0);
75        assert_eq!(0, z);
76        assert_eq!(0, x);
77        assert_eq!(0, y);
78        let (z, x, y) = pmid2zxy(1);
79        assert_eq!(1, z);
80        assert_eq!(0, x);
81        assert_eq!(0, y);
82        let (z, x, y) = pmid2zxy(19_078_479);
83        assert_eq!(12, z);
84        assert_eq!(3423, x);
85        assert_eq!(1763, y);
86    }
87
88    #[test]
89    fn test_many_tile_ids() {
90        for z in 0..10 {
91            for x in 0..(1 << z) {
92                for y in 0..(1 << z) {
93                    let id = zxy2pmid(z, x, y);
94                    let (rz, rx, ry) = pmid2zxy(id);
95                    assert_eq!(z, rz);
96                    assert_eq!(x, rx);
97                    assert_eq!(y, ry);
98                }
99            }
100        }
101    }
102
103    #[test]
104    fn test_extremes() {
105        for tz in 0..32 {
106            let dim = (1 << tz) - 1;
107            let (z, x, y) = pmid2zxy(zxy2pmid(tz, 0, 0));
108            assert_eq!(tz, z);
109            assert_eq!(0, x);
110            assert_eq!(0, y);
111            let (z, x, y) = pmid2zxy(zxy2pmid(z, dim, 0));
112            assert_eq!(tz, z);
113            assert_eq!(dim, x);
114            assert_eq!(0, y);
115            let (z, x, y) = pmid2zxy(zxy2pmid(z, 0, dim));
116            assert_eq!(tz, z);
117            assert_eq!(0, x);
118            assert_eq!(dim, y);
119            let (z, x, y) = pmid2zxy(zxy2pmid(z, dim, dim));
120            assert_eq!(tz, z);
121            assert_eq!(dim, x);
122            assert_eq!(dim, y);
123        }
124    }
125
126    #[test]
127    fn test_parent() {
128        assert_eq!(zxy2pmid(0, 0, 0), parent_id(zxy2pmid(1, 0, 0)));
129
130        assert_eq!(zxy2pmid(1, 0, 0), parent_id(zxy2pmid(2, 0, 0)));
131        assert_eq!(zxy2pmid(1, 0, 0), parent_id(zxy2pmid(2, 0, 1)));
132        assert_eq!(zxy2pmid(1, 0, 0), parent_id(zxy2pmid(2, 1, 0)));
133        assert_eq!(zxy2pmid(1, 0, 0), parent_id(zxy2pmid(2, 1, 1)));
134
135        assert_eq!(zxy2pmid(1, 0, 1), parent_id(zxy2pmid(2, 0, 2)));
136        assert_eq!(zxy2pmid(1, 0, 1), parent_id(zxy2pmid(2, 0, 3)));
137        assert_eq!(zxy2pmid(1, 0, 1), parent_id(zxy2pmid(2, 1, 2)));
138        assert_eq!(zxy2pmid(1, 0, 1), parent_id(zxy2pmid(2, 1, 3)));
139
140        assert_eq!(zxy2pmid(1, 1, 0), parent_id(zxy2pmid(2, 2, 0)));
141        assert_eq!(zxy2pmid(1, 1, 0), parent_id(zxy2pmid(2, 2, 1)));
142        assert_eq!(zxy2pmid(1, 1, 0), parent_id(zxy2pmid(2, 3, 0)));
143        assert_eq!(zxy2pmid(1, 1, 0), parent_id(zxy2pmid(2, 3, 1)));
144
145        assert_eq!(zxy2pmid(1, 1, 1), parent_id(zxy2pmid(2, 2, 2)));
146        assert_eq!(zxy2pmid(1, 1, 1), parent_id(zxy2pmid(2, 2, 3)));
147        assert_eq!(zxy2pmid(1, 1, 1), parent_id(zxy2pmid(2, 3, 2)));
148        assert_eq!(zxy2pmid(1, 1, 1), parent_id(zxy2pmid(2, 3, 3)));
149    }
150}