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();
|
let _ = io::stdout().flush();
|
||||||
|
|
||||||
// Populate job queue
|
// Populate job queue
|
||||||
let bucket_n = {
|
let hilbert_count = (thread_count as f32).sqrt() as u32;
|
||||||
let bucket_count_x = (width / bucket_size) + 1;
|
let (middle_bucket, bucket_n) = {
|
||||||
let bucket_count_y = (height / bucket_size) + 1;
|
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 larger = cmp::max(bucket_count_x, bucket_count_y);
|
||||||
let pow2 = upper_power_of_two(larger);
|
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 {
|
for hilbert_spiral_i in 0..bucket_n {
|
||||||
let (bx, by) = hilbert::decode(hilbert_d);
|
let (bx, by) =
|
||||||
|
crate::space_fill::hilbert_spiral::decode(hilbert_spiral_i, hilbert_count);
|
||||||
|
|
||||||
let x = bx * bucket_size;
|
let bx = middle_bucket.0 as i32 + bx;
|
||||||
let y = by * bucket_size;
|
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 {
|
let w = if width >= x {
|
||||||
min(bucket_size, width - x)
|
min(bucket_size, width - x)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -11,13 +11,13 @@ pub mod hilbert {
|
||||||
/// y: The y coordinate. Must be no greater than 2^16-1.
|
/// y: The y coordinate. Must be no greater than 2^16-1.
|
||||||
///
|
///
|
||||||
/// Returns the hilbert curve index corresponding to the (x,y) coordinates given.
|
/// 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!(x < N);
|
||||||
assert!(y < N);
|
assert!(y < N);
|
||||||
|
|
||||||
let (mut x, mut y) = (x, y);
|
let (mut x, mut y) = (x, y);
|
||||||
let mut d = 0;
|
let mut d = 0;
|
||||||
let mut s = N >> 1;
|
let mut s = n >> 1;
|
||||||
while s > 0 {
|
while s > 0 {
|
||||||
let rx = if (x & s) > 0 { 1 } else { 0 };
|
let rx = if (x & s) > 0 { 1 } else { 0 };
|
||||||
let ry = if (y & 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.
|
/// d: The hilbert curve index.
|
||||||
///
|
///
|
||||||
/// Returns the (x, y) coords at the given 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 x, mut y) = (0, 0);
|
||||||
let mut s = 1;
|
let mut s = 1;
|
||||||
let mut t = d;
|
let mut t = d;
|
||||||
while s < N {
|
while s < n {
|
||||||
let rx = 1 & (t >> 1);
|
let rx = 1 & (t >> 1);
|
||||||
let ry = 1 & (t ^ rx);
|
let ry = 1 & (t ^ rx);
|
||||||
(x, y) = hilbert_rotate(s, rx, ry, x, y);
|
(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)]
|
#[cfg(test)]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user