core: add 2D hilbert curve table support

This commit is contained in:
Alain Zscheile 2023-01-08 06:57:37 +01:00
parent b440739715
commit 607b87cb77
2 changed files with 91 additions and 0 deletions

View file

@ -0,0 +1,48 @@
/// rotate/flip a quadrant
fn rot(n: u32, x: &mut u32, y: &mut u32, rx: bool, ry: bool) {
if ry {
return;
}
if rx {
*x = n - 1 - *x;
*y = n - 1 - *y;
}
core::mem::swap(x, y);
}
fn bool2int(x: bool) -> u32 {
if x {
1
} else {
0
}
}
pub fn xy2d(nh: u8, mut x: u32, mut y: u32) -> u32 {
let n = 1 << nh;
(0..nh)
.rev()
.map(|sh| {
let s = 1u32 << sh;
let rx = (x & s) != 0;
let ry = (y & s) != 0;
rot(n, &mut x, &mut y, rx, ry);
s * s * ((3 * bool2int(rx)) ^ bool2int(ry))
})
.sum()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn simple() {
let exp: [u32; 16] = [0, 3, 4, 5, 1, 2, 7, 6, 14, 13, 8, 9, 15, 12, 11, 10];
for x in 0..4u16 {
for y in 0..4u16 {
assert_eq!(exp[usize::from(x * 4 + y)], xy2d(4, x.into(), y.into()));
}
}
}
}

View file

@ -3,6 +3,8 @@
use int_enum::IntEnum;
pub mod hilbert;
mod ht;
pub use ht::*;
@ -69,3 +71,44 @@ pub fn linear_table_iter(
rest: &i[16..],
})
}
#[derive(Clone, Copy)]
pub struct X2dhc<'a> {
xybits: u8,
data: &'a [u8],
}
impl<'a> X2dhc<'a> {
pub fn parse(data: &'a [u8], entsize: u16, entcount: u16) -> Option<Self> {
if entsize != 1 {
return None;
}
let data = data.get(..(16 * usize::from(entcount)))?;
if data.len() < 32 {
return None;
}
let xybits = data[0];
if xybits >= 8 {
return None;
}
let exp_len = 1usize.checked_shl(xybits.into())?.checked_mul(16)?;
if (data.len() - 16) != exp_len {
return None;
}
Some(Self {
xybits,
data: &data[16..],
})
}
pub fn x2dhc_lookup(&self, x: u8, y: u8) -> (u64, u64) {
let xybr = 8 - self.xybits;
let (x, y) = (x >> xybr, y >> xybr);
let loc = 16 * usize::try_from(hilbert::xy2d(2 * self.xybits, x.into(), y.into())).unwrap();
let dloc = &self.data[loc..loc + 16];
(
u64::from_be_bytes(dloc[0..8].try_into().unwrap()),
u64::from_be_bytes(dloc[8..16].try_into().unwrap()),
)
}
}