Thanks. The actual code, non-iterator, is below. Not runnable without a lot more code.
This is part of the tiling algorithm for a slippy map. It's for distant impostors in a 3D world. There's a hierarchy of map tiles (they're 3D objects here), and if you're close to the camera, smaller tiles with more detail have to be used. It's like Google Earth.
I was kind of hoping to get an iterator out, because the next step is a filter which checks which ones we already are drawing and computes the changes. But the actual number of tiles that comes out of this process is around 50, even for a world thousands of tiles across, because most are not subdivided. So overhead is not large. Using an iterator would just be a style thing.
/// Calculate relevant tiles.
/// Recursively subdivides the tiles, discarding any exclude regions.
///
/// If there's no overlap with the exclude regions, return this tile.
/// Otherwise subdivide into quadrants and try again.
fn calculate_impostorable_tiles(base_tile_size: [u32;2], tile: RegionBox, exclude_regions: &[RegionBox]) -> Vec<RegionBox> {
println!("Impostorable tile: {:?}", tile); // ***TEMP***
// Sanity check on input
check_valid_tile(base_tile_size, &tile);
// Does this tile overlap any regions we can't impostor?
if exclude_regions.iter().find(|&item| item.overlap(tile)).is_none() {
return vec![tile]
}
// Check if further subdivision possible.
if tile.size[0] <= base_tile_size[0] || tile.size[1] <= base_tile_size[1] {
return vec![]; // done
}
// Yes, there is overlap. Divide tile into four quadrants and recurse.
let halfsizex = tile.size[0] / 2;
let halfsizey = tile.size[1] / 2;
let halfsize = [halfsizex, halfsizey];
//////let halflod = tile.1 - 1;
let pos = tile.region_handle.to_region_loc_u32();
// Create a quadrant
let subtile = |offset: [u32;2]| RegionBox {
region_handle: RegionHandle::from_region_loc([pos[0] + halfsizex * offset[0], pos[1] + halfsizey * offset[1]]),
size: halfsize
};
// Concatenate results from the four quadrants
let mut subtiles = calculate_impostorable_tiles(base_tile_size, subtile([0,0]), exclude_regions);
subtiles.extend(calculate_impostorable_tiles(base_tile_size, subtile([1,0]), exclude_regions));
subtiles.extend(calculate_impostorable_tiles(base_tile_size, subtile([0,1]), exclude_regions));
subtiles.extend(calculate_impostorable_tiles(base_tile_size, subtile([1,1]), exclude_regions));
subtiles
}
The part at the end is the recursion. I'd tried doing that with Chain
, but, as others pointed out, that won't work easily, if at all.