Implement "hilbert spiral" bucket rendering order.
This commit is contained in:
parent
7c750dcded
commit
77ac8ef9f2
|
@ -118,18 +118,32 @@ impl<'a> Renderer<'a> {
|
|||
let _ = io::stdout().flush();
|
||||
|
||||
// Populate job queue
|
||||
let bucket_n = {
|
||||
let bucket_count_x = (width / bucket_size) + 1;
|
||||
let bucket_count_y = (height / bucket_size) + 1;
|
||||
let hilbert_count = (thread_count as f32).sqrt() as u32;
|
||||
let (middle_bucket, bucket_n) = {
|
||||
let bucket_count_x =
|
||||
(width / bucket_size) + if (width % bucket_size) != 0 { 1 } else { 0 };
|
||||
let bucket_count_y =
|
||||
(height / bucket_size) + if (height % bucket_size) != 0 { 1 } else { 0 };
|
||||
let larger = cmp::max(bucket_count_x, bucket_count_y);
|
||||
let pow2 = upper_power_of_two(larger);
|
||||
pow2 * pow2
|
||||
let buffer = hilbert_count; // For hilbert spiral.
|
||||
(
|
||||
(bucket_count_x / 2, bucket_count_y / 2),
|
||||
(pow2 + buffer) * (pow2 + buffer),
|
||||
)
|
||||
};
|
||||
for hilbert_d in 0..bucket_n {
|
||||
let (bx, by) = hilbert::decode(hilbert_d);
|
||||
for hilbert_spiral_i in 0..bucket_n {
|
||||
let (bx, by) =
|
||||
crate::space_fill::hilbert_spiral::decode(hilbert_spiral_i, hilbert_count);
|
||||
|
||||
let x = bx * bucket_size;
|
||||
let y = by * bucket_size;
|
||||
let bx = middle_bucket.0 as i32 + bx;
|
||||
let by = middle_bucket.1 as i32 + by;
|
||||
if bx < 0 || by < 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let x = bx as u32 * bucket_size;
|
||||
let y = by as u32 * bucket_size;
|
||||
let w = if width >= x {
|
||||
min(bucket_size, width - x)
|
||||
} else {
|
||||
|
|
|
@ -11,13 +11,13 @@ pub mod hilbert {
|
|||
/// y: The y coordinate. Must be no greater than 2^16-1.
|
||||
///
|
||||
/// Returns the hilbert curve index corresponding to the (x,y) coordinates given.
|
||||
pub fn encode(x: u32, y: u32) -> u32 {
|
||||
pub fn encode(x: u32, y: u32, n: u32) -> u32 {
|
||||
assert!(x < N);
|
||||
assert!(y < N);
|
||||
|
||||
let (mut x, mut y) = (x, y);
|
||||
let mut d = 0;
|
||||
let mut s = N >> 1;
|
||||
let mut s = n >> 1;
|
||||
while s > 0 {
|
||||
let rx = if (x & s) > 0 { 1 } else { 0 };
|
||||
let ry = if (y & s) > 0 { 1 } else { 0 };
|
||||
|
@ -35,11 +35,11 @@ pub mod hilbert {
|
|||
/// d: The hilbert curve index.
|
||||
///
|
||||
/// Returns the (x, y) coords at the given index.
|
||||
pub fn decode(d: u32) -> (u32, u32) {
|
||||
pub fn decode(d: u32, n: u32) -> (u32, u32) {
|
||||
let (mut x, mut y) = (0, 0);
|
||||
let mut s = 1;
|
||||
let mut t = d;
|
||||
while s < N {
|
||||
while s < n {
|
||||
let rx = 1 & (t >> 1);
|
||||
let ry = 1 & (t ^ rx);
|
||||
(x, y) = hilbert_rotate(s, rx, ry, x, y);
|
||||
|
@ -118,6 +118,76 @@ pub mod morton {
|
|||
}
|
||||
}
|
||||
|
||||
/// Yields coordinates in outward spiral, but incorporating a Hilbert
|
||||
/// curve at the smaller scales.
|
||||
pub mod hilbert_spiral {
|
||||
/// Convert from hilbert-spiral index to (x,y).
|
||||
///
|
||||
/// Note: this returns both negative and positive coordinates.
|
||||
/// It starts at 0,0 and spirals outwards.
|
||||
///
|
||||
/// i: The hilbert-spiral index.
|
||||
/// hilbert_size: the size of the hulbert blocks on a side. Will be
|
||||
/// rounded down to the nearest power of two.
|
||||
///
|
||||
/// Returns the (x, y) coords at the given index.
|
||||
pub fn decode(i: u32, hilbert_size: u32) -> (i32, i32) {
|
||||
assert!(hilbert_size > 0);
|
||||
let hilbert_size = 1 << (31 - u32::leading_zeros(hilbert_size));
|
||||
|
||||
let hilbert_cells = hilbert_size * hilbert_size;
|
||||
|
||||
let hilbert_i = i % hilbert_cells;
|
||||
let spiral_i = i / hilbert_cells;
|
||||
|
||||
let (mut sx, mut sy, section) = decode_spiral(spiral_i);
|
||||
sx = (sx * hilbert_size as i32) - (hilbert_size / 2) as i32;
|
||||
sy = (sy * hilbert_size as i32) - (hilbert_size / 2) as i32;
|
||||
|
||||
let (hx, hy) = {
|
||||
let (hx, hy) = super::hilbert::decode(hilbert_i, hilbert_size);
|
||||
let a = hilbert_size - 1;
|
||||
match section {
|
||||
0 => (hx, a - hy),
|
||||
1 => (a - hy, hx),
|
||||
2 => (a - hx, hy),
|
||||
3 => (hy, a - hx),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
};
|
||||
|
||||
(sx + hx as i32, sy + hy as i32)
|
||||
}
|
||||
|
||||
pub fn decode_spiral(i: u32) -> (i32, i32, u32) {
|
||||
if i == 0 {
|
||||
return (0, 0, 3);
|
||||
}
|
||||
|
||||
// 0 = first ring outside of center, 1 = second, and so on.
|
||||
let ring = (((i as f64).sqrt() - 1.0) / 2.0) as u32;
|
||||
|
||||
// The size of the ring along one side.
|
||||
let size = 1 + ((ring + 1) * 2);
|
||||
|
||||
let n = i - ((size - 2) * (size - 2)); // The zero-indexed cell of the ring.
|
||||
let arm = n / (size - 1); // The arm of the ring.
|
||||
let arm_n = n % (size - 1); // The index within the arm of the ring.
|
||||
|
||||
// The two coordinates. They just need to be flipped around depending on the arm.
|
||||
let radius = ring as i32 + 1;
|
||||
let d = -(size as i32 / 2) + 1 + arm_n as i32;
|
||||
|
||||
match arm {
|
||||
0 => (d, -radius, 0),
|
||||
1 => (radius, d, if arm_n == (size - 2) { 2 } else { 1 }),
|
||||
2 => (-d, radius, 2),
|
||||
3 => (-radius, -d, 3),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
Loading…
Reference in New Issue
Block a user