#![cfg_attr(not(test), no_std)]
use core::convert::{From, TryInto};
use core::fmt::Debug;
use core::ops::{BitAnd, BitOr, BitOrAssign, Not, Shl, ShlAssign, Shr, ShrAssign, Sub};
#[cfg(feature = "checked")]
mod checked;
#[cfg(feature = "checked")]
pub use checked::{h2xy_checked, max_coord, max_index, max_order, xy2h_checked, OrderError};
pub trait UnsignedBase:
From<u8>
+ Copy
+ TryInto<usize>
+ BitOrAssign
+ BitOr<Output = Self>
+ BitAnd<Output = Self>
+ Shl<i8, Output = Self>
+ Shr<i8, Output = Self>
+ Shl<usize, Output = Self>
+ Shr<usize, Output = Self>
+ ShrAssign
+ ShlAssign
+ Sub<Self, Output = Self>
+ Not<Output = Self>
+ Ord
+ Debug
{
fn leading_zeros(self) -> u32;
fn as_usize(self) -> usize;
fn as_u8(self) -> u8;
const ZERO: Self;
}
macro_rules! base_impl {
($T:ty) => {
impl UnsignedBase for $T {
const ZERO: Self = 0;
#[inline]
fn leading_zeros(self) -> u32 {
<$T>::leading_zeros(self)
}
#[inline]
fn as_usize(self) -> usize {
self as usize
}
#[inline]
fn as_u8(self) -> u8 {
self as u8
}
}
};
}
base_impl!(u128);
base_impl!(u64);
base_impl!(u32);
base_impl!(u16);
base_impl!(u8);
pub trait Unsigned: UnsignedBase + Into<Self::Key>
where
Self::Key: UnsignedBase,
{
type Key; const SEVEN: Self; const SIXTY_THREE: Self::Key; }
impl Unsigned for u64 {
type Key = u128;
const SEVEN: Self = 7;
const SIXTY_THREE: Self::Key = 63;
}
impl Unsigned for u32 {
type Key = u64;
const SEVEN: Self = 7;
const SIXTY_THREE: Self::Key = 63;
}
impl Unsigned for u16 {
type Key = u32;
const SEVEN: Self = 7;
const SIXTY_THREE: Self::Key = 63;
}
impl Unsigned for u8 {
type Key = u16;
const SEVEN: Self = 7;
const SIXTY_THREE: Self::Key = 63;
}
pub fn xy2h<T: Unsigned>(x: T, y: T, order: u8) -> <T as Unsigned>::Key {
const LUT_3: [u8; 256] = [
64, 1, 206, 79, 16, 211, 84, 21, 131, 2, 205, 140, 81, 82, 151, 22, 4, 199, 8, 203, 158,
157, 88, 25, 69, 70, 73, 74, 31, 220, 155, 26, 186, 185, 182, 181, 32, 227, 100, 37, 59,
248, 55, 244, 97, 98, 167, 38, 124, 61, 242, 115, 174, 173, 104, 41, 191, 62, 241, 176, 47,
236, 171, 42, 0, 195, 68, 5, 250, 123, 60, 255, 65, 66, 135, 6, 249, 184, 125, 126, 142,
141, 72, 9, 246, 119, 178, 177, 15, 204, 139, 10, 245, 180, 51, 240, 80, 17, 222, 95, 96,
33, 238, 111, 147, 18, 221, 156, 163, 34, 237, 172, 20, 215, 24, 219, 36, 231, 40, 235, 85,
86, 89, 90, 101, 102, 105, 106, 170, 169, 166, 165, 154, 153, 150, 149, 43, 232, 39, 228,
27, 216, 23, 212, 108, 45, 226, 99, 92, 29, 210, 83, 175, 46, 225, 160, 159, 30, 209, 144,
48, 243, 116, 53, 202, 75, 12, 207, 113, 114, 183, 54, 201, 136, 77, 78, 190, 189, 120, 57,
198, 71, 130, 129, 63, 252, 187, 58, 197, 132, 3, 192, 234, 107, 44, 239, 112, 49, 254,
127, 233, 168, 109, 110, 179, 50, 253, 188, 230, 103, 162, 161, 52, 247, 56, 251, 229, 164,
35, 224, 117, 118, 121, 122, 218, 91, 28, 223, 138, 137, 134, 133, 217, 152, 93, 94, 11,
200, 7, 196, 214, 87, 146, 145, 76, 13, 194, 67, 213, 148, 19, 208, 143, 14, 193, 128,
];
let coor_bits = (size_of::<T>() << 3) as u32;
let useless_bits = (x | y).leading_zeros() & !1;
let lowest_order = (coor_bits - useless_bits) as u8 + (order & 1);
let mut result: T::Key = T::Key::ZERO;
let mut state = 0u8;
let mut shift_factor = lowest_order as i8 - 3;
while shift_factor > 0 {
let x_in = ((x >> shift_factor) & T::SEVEN) << 3i8;
let y_in = (y >> shift_factor) & T::SEVEN;
let index = (x_in | y_in | state.into()).as_usize();
let r = LUT_3[index];
state = r & 0b1100_0000;
let r: T::Key = r.into();
let mut hhh: T::Key = r & T::SIXTY_THREE;
hhh <<= ((shift_factor as u8) << 1).into();
result |= hhh;
shift_factor -= 3;
}
shift_factor *= -1;
let x_in = ((x << shift_factor) & T::SEVEN) << 3i8;
let y_in = (y << shift_factor) & T::SEVEN;
let index = (x_in | y_in | state.into()).as_usize();
let r: u8 = LUT_3[index];
let r: T::Key = r.into();
let mut hhh: T::Key = r & T::SIXTY_THREE;
hhh >>= ((shift_factor as u8) << 1).into();
result | hhh
}
pub fn h2xy<T: Unsigned>(h: <T as Unsigned>::Key, order: u8) -> (T, T) {
const LUT_3_REV: [u8; 256] = [
64, 1, 9, 136, 16, 88, 89, 209, 18, 90, 91, 211, 139, 202, 194, 67, 4, 76, 77, 197, 70, 7,
15, 142, 86, 23, 31, 158, 221, 149, 148, 28, 36, 108, 109, 229, 102, 39, 47, 174, 118, 55,
63, 190, 253, 181, 180, 60, 187, 250, 242, 115, 235, 163, 162, 42, 233, 161, 160, 40, 112,
49, 57, 184, 0, 72, 73, 193, 66, 3, 11, 138, 82, 19, 27, 154, 217, 145, 144, 24, 96, 33,
41, 168, 48, 120, 121, 241, 50, 122, 123, 243, 171, 234, 226, 99, 100, 37, 45, 172, 52,
124, 125, 245, 54, 126, 127, 247, 175, 238, 230, 103, 223, 151, 150, 30, 157, 220, 212, 85,
141, 204, 196, 69, 6, 78, 79, 199, 255, 183, 182, 62, 189, 252, 244, 117, 173, 236, 228,
101, 38, 110, 111, 231, 159, 222, 214, 87, 207, 135, 134, 14, 205, 133, 132, 12, 84, 21,
29, 156, 155, 218, 210, 83, 203, 131, 130, 10, 201, 129, 128, 8, 80, 17, 25, 152, 32, 104,
105, 225, 98, 35, 43, 170, 114, 51, 59, 186, 249, 177, 176, 56, 191, 254, 246, 119, 239,
167, 166, 46, 237, 165, 164, 44, 116, 53, 61, 188, 251, 179, 178, 58, 185, 248, 240, 113,
169, 232, 224, 97, 34, 106, 107, 227, 219, 147, 146, 26, 153, 216, 208, 81, 137, 200, 192,
65, 2, 74, 75, 195, 68, 5, 13, 140, 20, 92, 93, 213, 22, 94, 95, 215, 143, 206, 198, 71,
];
let coor_bits = (size_of::<T>() << 3) as u8;
let useless_bits = (h.leading_zeros() >> 1) as u8 & !1;
let lowest_order = coor_bits - useless_bits + (order & 1);
let mut x_result: T = T::ZERO;
let mut y_result: T = x_result;
let mut state = 0u8;
let mut shift_factor = lowest_order as i8 - 3;
while shift_factor > 0 {
let h_in: T::Key = h >> ((shift_factor as usize) << 1);
let h_in: T::Key = h_in & T::SIXTY_THREE;
let h_in: u8 = h_in.as_u8();
let r: u8 = LUT_3_REV[state as usize | h_in as usize];
state = r & 0b1100_0000;
let xxx: T = r.into();
let xxx: T = xxx >> 3i8;
let xxx: T = xxx & T::SEVEN;
let yyy: T = r.into();
let yyy: T = yyy & T::SEVEN;
x_result |= xxx << shift_factor;
y_result |= yyy << shift_factor;
shift_factor -= 3;
}
shift_factor *= -1;
let h_in: T::Key = h << ((shift_factor as usize) << 1);
let h_in: T::Key = h_in & T::SIXTY_THREE;
let h_in: u8 = h_in.as_u8();
let r: u8 = LUT_3_REV[state as usize | h_in as usize];
let xxx: T = r.into();
let xxx: T = xxx >> 3i8;
let xxx: T = xxx & T::SEVEN;
let yyy: T = r.into();
let yyy: T = yyy & T::SEVEN;
x_result = xxx >> shift_factor | x_result;
y_result = yyy >> shift_factor | y_result;
(x_result, y_result)
}
#[cfg(test)]
mod tests {
const LUT_SXY2SH: [u8; 16] = [4, 1, 11, 2, 0, 15, 5, 6, 10, 9, 3, 12, 14, 7, 13, 8];
const LUT_SH2SXY: [u8; 16] = [
0b0100, 0b0001, 0b0011, 0b1010, 0b0000, 0b0110, 0b0111, 0b1101, 0b1111, 0b1001, 0b1000, 0b0010, 0b1011, 0b1110, 0b1100, 0b0101,
];
use super::*;
extern crate image;
#[test]
fn gen_lut3_sxxxyyy() {
let mut lut_3: [u8; 256] = [0; 256];
for input in 0..=255 {
let mut state: u8 = (input & 0b1100_0000) >> 4;
let mut result: u8 = 0;
let mut x_mask: u8 = 0b0010_0000;
let mut y_mask: u8 = 0b0000_0100;
for i in 0..3 {
let idx = state | (input & x_mask) >> (4 - i) | (input & y_mask) >> (2 - i);
let r = LUT_SXY2SH[idx as usize];
state = r & 0b1100;
result = (result & 0b0011_1111) | (state << 4);
result = (result & !(0b0011_0000 >> (i * 2))) | ((r & 0b0011) << ((2 - i) * 2));
x_mask >>= 1;
y_mask >>= 1;
}
lut_3[input as usize] = result;
}
println!("{lut_3:?}");
}
#[test]
fn gen_lut3_shhh() {
let mut lut_3: [u8; 256] = [0; 256];
for input in 0..=255 {
let mut state: u8 = (input & 0b1100_0000) >> 6;
let mut result: u8 = 0;
let mut h_mask: u8 = 0b0011_0000;
for i in 0..3 {
let idx = (state << 2) | (input & h_mask) >> (4 - (i * 2));
let r = LUT_SH2SXY[idx as usize];
state = (r & 0b1100) >> 2;
let x = (r & 0b10) >> 1;
let y = r & 0b1;
result = (result & 0b0011_1111) | (state << 6);
result = (result & !(0b0010_0000 >> i)) | (x << (5 - i));
result = (result & !(0b0000_0100 >> i)) | (y << (2 - i));
h_mask >>= 2;
}
lut_3[input as usize] = result;
}
println!("{lut_3:?}");
}
#[test]
fn hilbert_and_rev() {
let order = 4;
let max = 2usize.pow(order * 2);
for h in 0..max {
let (x, y): (u32, u32) = h2xy(h as u64, order as u8);
let res_h = xy2h(x, y, order as u8);
assert_eq!(h as u64, res_h);
}
}
#[test]
fn hilbert_and_rev_full_order() {
let order = 8;
let max = 2usize.pow(order * 2);
for h in 0..max {
let (x, y): (u8, u8) = h2xy(h as u16, order as u8);
let res_h = xy2h(x, y, order as u8);
assert_eq!(h as u16, res_h);
}
}
#[test]
fn h2xy_one_bit() {
let h2xy = h2xy::<u8>;
let (x0, y0) = h2xy(0, 1);
let (x1, y1) = h2xy(1, 1);
let (x2, y2) = h2xy(2, 1);
let (x3, y3) = h2xy(3, 1);
assert_eq!((x0, y0), (0, 0));
assert_eq!((x1, y1), (0, 1));
assert_eq!((x2, y2), (1, 1));
assert_eq!((x3, y3), (1, 0));
}
#[test]
fn xy2h_one_bit() {
let d0 = xy2h(0u64, 0, 1);
let d1 = xy2h(0u64, 1, 1);
let d2 = xy2h(1u64, 0, 1);
let d3 = xy2h(1u64, 1, 1);
assert_eq!(d0, 0);
assert_eq!(d1, 1);
assert_eq!(d2, 3);
assert_eq!(d3, 2);
}
#[test]
fn h2xy_two_bits() {
let h2xy = h2xy::<u32>;
for h in 0..8 {
let (rx, ry) = h2xy(h as u64, 2);
let h_cmp = xy2h(rx, ry, 2);
assert_eq!(h, h_cmp as usize);
}
}
#[test]
fn xy2h_two_bits() {
for x in 0..4 {
for y in 0..4 {
let d = hilbert_curve::convert_2d_to_1d(x, y, 4);
let df = xy2h(x as u32, y as u32, 2);
assert_eq!(d as u64, df);
}
}
}
#[test]
fn h2xy_test() {
for &bits in &[1, 2, 3, 5, 8, 13, 16] {
let bits = (bits + 1) & !1;
let numbers = 2usize.pow(bits);
for d in (0..(numbers * numbers)).step_by(numbers) {
let (x, y) = hilbert_curve::convert_1d_to_2d(d, numbers);
assert_eq!(xy2h(x as u32, y as u32, bits as u8), d as u64);
}
}
}
#[allow(clippy::cast_precision_loss, clippy::needless_range_loop)]
fn draw_hilbert_curve(iteration: u32) -> image::ImageBuffer<image::Rgb<u8>, Vec<u8>> {
let size: usize = 256;
let border = 32 / iteration;
let mut imgbuf = image::ImageBuffer::new(size as u32, size as u32);
let mut points: Vec<(u32, u32)> = vec![(0, 0); 2usize.pow(iteration * 2)];
for i in 0..2usize.pow(iteration * 2) {
let (mut x, mut y) = h2xy(i as u64, iteration as u8);
let step = f64::from(size as u32 - border * 2) / (2usize.pow(iteration) as f64 - 1.0);
x = (f64::from(x) * step) as u32 + border;
y = (f64::from(y) * step) as u32 + border;
points[i] = (x, y);
}
let mut prev = (0, 0);
let white = image::Rgb([255_u8, 255, 255]);
for (x, y) in &points {
if prev == (0, 0) {
prev = (*x, *y);
continue;
}
while prev.0 < *x {
let pixel = imgbuf.get_pixel_mut(prev.0, prev.1);
*pixel = white;
prev.0 += 1;
}
while prev.0 > *x {
let pixel = imgbuf.get_pixel_mut(prev.0, prev.1);
*pixel = white;
prev.0 -= 1;
}
while prev.1 < *y {
let pixel = imgbuf.get_pixel_mut(prev.0, prev.1);
*pixel = white;
prev.1 += 1;
}
while prev.1 > *y {
let pixel = imgbuf.get_pixel_mut(prev.0, prev.1);
*pixel = white;
prev.1 -= 1;
}
}
imgbuf
}
#[test]
fn write_image() {
for i in 1..7 {
let imgbuf = draw_hilbert_curve(i);
imgbuf.save(format!("doc/h{i}.png")).unwrap();
}
}
}