use crate::int_2_offset_zoom;
#[must_use]
pub fn xyz2pmid(x: u32, y: u32, z: u8) -> u64 {
if z == 0 {
return 0;
}
let base_id: u64 = (4u64.pow(u32::from(z)) - 1) / 3;
let h = fast_hilbert::xy2h(x, y, z);
base_id + h
}
#[must_use]
pub fn zxy2pmid(z: u8, x: u32, y: u32) -> u64 {
xyz2pmid(x, y, z)
}
#[must_use]
pub fn pmid2xyz(i: u64) -> (u32, u32, u8) {
if i == 0 {
return (0, 0, 0);
}
let (i_o, z) = int_2_offset_zoom(i);
let (x, y) = fast_hilbert::h2xy(i_o, z);
(x, y, z)
}
#[must_use]
pub fn pmid2zxy(i: u64) -> (u8, u32, u32) {
let (x, y, z) = pmid2xyz(i);
(z, x, y)
}
#[must_use]
pub const fn parent_id(i: u64) -> u64 {
let mut acc: u64 = 0;
let mut last_acc: u64 = 0;
let mut z: u8 = 0;
loop {
let num_tiles: u64 = (1 << z) * (1 << z);
if acc + num_tiles > i {
return last_acc + (i - acc) / 4;
}
last_acc = acc;
acc += num_tiles;
z += 1;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_zxy_to_id() {
assert_eq!(0, zxy2pmid(0, 0, 0));
assert_eq!(1, zxy2pmid(1, 0, 0));
assert_eq!(2, zxy2pmid(1, 0, 1));
assert_eq!(3, zxy2pmid(1, 1, 1));
assert_eq!(4, zxy2pmid(1, 1, 0));
assert_eq!(5, zxy2pmid(2, 0, 0));
}
#[test]
fn test_id_to_zxy() {
let (z, x, y) = pmid2zxy(0);
assert_eq!(0, z);
assert_eq!(0, x);
assert_eq!(0, y);
let (z, x, y) = pmid2zxy(1);
assert_eq!(1, z);
assert_eq!(0, x);
assert_eq!(0, y);
let (z, x, y) = pmid2zxy(19_078_479);
assert_eq!(12, z);
assert_eq!(3423, x);
assert_eq!(1763, y);
}
#[test]
fn test_many_tile_ids() {
for z in 0..10 {
for x in 0..(1 << z) {
for y in 0..(1 << z) {
let id = zxy2pmid(z, x, y);
let (rz, rx, ry) = pmid2zxy(id);
assert_eq!(z, rz);
assert_eq!(x, rx);
assert_eq!(y, ry);
}
}
}
}
#[test]
fn test_extremes() {
for tz in 0..32 {
let dim = (1 << tz) - 1;
let (z, x, y) = pmid2zxy(zxy2pmid(tz, 0, 0));
assert_eq!(tz, z);
assert_eq!(0, x);
assert_eq!(0, y);
let (z, x, y) = pmid2zxy(zxy2pmid(z, dim, 0));
assert_eq!(tz, z);
assert_eq!(dim, x);
assert_eq!(0, y);
let (z, x, y) = pmid2zxy(zxy2pmid(z, 0, dim));
assert_eq!(tz, z);
assert_eq!(0, x);
assert_eq!(dim, y);
let (z, x, y) = pmid2zxy(zxy2pmid(z, dim, dim));
assert_eq!(tz, z);
assert_eq!(dim, x);
assert_eq!(dim, y);
}
}
#[test]
fn test_parent() {
assert_eq!(zxy2pmid(0, 0, 0), parent_id(zxy2pmid(1, 0, 0)));
assert_eq!(zxy2pmid(1, 0, 0), parent_id(zxy2pmid(2, 0, 0)));
assert_eq!(zxy2pmid(1, 0, 0), parent_id(zxy2pmid(2, 0, 1)));
assert_eq!(zxy2pmid(1, 0, 0), parent_id(zxy2pmid(2, 1, 0)));
assert_eq!(zxy2pmid(1, 0, 0), parent_id(zxy2pmid(2, 1, 1)));
assert_eq!(zxy2pmid(1, 0, 1), parent_id(zxy2pmid(2, 0, 2)));
assert_eq!(zxy2pmid(1, 0, 1), parent_id(zxy2pmid(2, 0, 3)));
assert_eq!(zxy2pmid(1, 0, 1), parent_id(zxy2pmid(2, 1, 2)));
assert_eq!(zxy2pmid(1, 0, 1), parent_id(zxy2pmid(2, 1, 3)));
assert_eq!(zxy2pmid(1, 1, 0), parent_id(zxy2pmid(2, 2, 0)));
assert_eq!(zxy2pmid(1, 1, 0), parent_id(zxy2pmid(2, 2, 1)));
assert_eq!(zxy2pmid(1, 1, 0), parent_id(zxy2pmid(2, 3, 0)));
assert_eq!(zxy2pmid(1, 1, 0), parent_id(zxy2pmid(2, 3, 1)));
assert_eq!(zxy2pmid(1, 1, 1), parent_id(zxy2pmid(2, 2, 2)));
assert_eq!(zxy2pmid(1, 1, 1), parent_id(zxy2pmid(2, 2, 3)));
assert_eq!(zxy2pmid(1, 1, 1), parent_id(zxy2pmid(2, 3, 2)));
assert_eq!(zxy2pmid(1, 1, 1), parent_id(zxy2pmid(2, 3, 3)));
}
}