pub fn decode_hilbert(index: u64, bits: u32) -> [u32; 3] {
let mut axes = [
compact3(index >> 2) as u32,
compact3(index >> 1) as u32,
compact3(index) as u32,
];
let gray = axes[2] >> 1;
axes[2] ^= axes[1];
axes[1] ^= axes[0];
axes[0] ^= gray;
let size = 1u32 << bits;
let mut mask = 2u32;
let mut shift = 1u32;
while mask != size {
let lower = mask - 1;
for i in (0..3).rev() {
let m = ((axes[i] >> shift) & 1).wrapping_neg();
let t = (axes[0] ^ axes[i]) & lower;
axes[0] ^= t ^ (m & (t ^ lower));
axes[i] ^= t & !m;
}
mask <<= 1;
shift += 1;
}
axes
}
fn compact3(mut x: u64) -> u64 {
x &= 0x1249249249249249;
x = (x | x >> 2) & 0x10c30c30c30c30c3;
x = (x | x >> 4) & 0x100f00f00f00f00f;
x = (x | x >> 8) & 0x1f0000ff0000ff;
x = (x | x >> 16) & 0x1f00000000ffff;
x = (x | x >> 32) & 0x1fffff;
x
}
#[cfg(test)]
mod tests {
use crate::{decode_hilbert, encode_hilbert};
#[test]
fn matches_spec_example() {
assert_eq!(decode_hilbert(0, 1), [0, 0, 0]);
assert_eq!(decode_hilbert(3, 1), [0, 1, 0]);
assert_eq!(decode_hilbert(4, 1), [1, 1, 0]);
assert_eq!(decode_hilbert(7, 1), [1, 0, 0]);
}
#[test]
fn round_trips_over_a_cube() {
let bits = 5; for x in 0..32 {
for y in 0..32 {
for z in 0..32 {
let i = encode_hilbert(x, y, z, bits);
assert_eq!(decode_hilbert(i, bits), [x, y, z]);
}
}
}
}
}