use std::ops;
use itertools;
use grid::{Root, GridCoord, GridPoint3};
use super::ChunkOrigin;
pub struct ChunkSharedPoints {
root: Root,
x_min: GridCoord,
x_max: GridCoord,
y_min: GridCoord,
y_max: GridCoord,
iter: itertools::ConsTuples<
itertools::Product<
itertools::Product<
ops::Range<GridCoord>,
ops::Range<GridCoord>,
>,
ops::Range<GridCoord>,
>,
((GridCoord, GridCoord), GridCoord),
>,
}
impl ChunkSharedPoints {
pub fn new(chunk_origin: ChunkOrigin, chunk_resolution: [GridCoord; 3]) -> ChunkSharedPoints {
let pos = chunk_origin.pos();
let iter = iproduct!(
pos.x..(pos.x + chunk_resolution[0] + 1),
pos.y..(pos.y + chunk_resolution[1] + 1),
pos.z..(pos.z + chunk_resolution[2])
);
ChunkSharedPoints {
root: pos.root,
x_min: pos.x,
x_max: pos.x + chunk_resolution[0],
y_min: pos.y,
y_max: pos.y + chunk_resolution[1],
iter: iter,
}
}
}
impl Iterator for ChunkSharedPoints {
type Item = GridPoint3;
fn next(&mut self) -> Option<GridPoint3> {
if let Some(xyz) = self.iter.next() {
let (x, y, z) = xyz;
let is_x_lim = x == self.x_min || x == self.x_max;
let is_y_lim = y == self.y_min || y == self.y_max;
let is_shared_point = is_x_lim || is_y_lim;
if is_shared_point {
Some(GridPoint3::new(self.root, x, y, z))
} else {
self.next()
}
} else {
None
}
}
}
#[cfg(test)]
mod tests {
use std::collections::HashSet;
use super::*;
#[test]
fn chunk_shared_points() {
const ROOT_RESOLUTION: [GridCoord; 2] = [16, 32];
const CHUNK_RESOLUTION: [GridCoord; 3] = [8, 8, 64];
let chunk_origin = ChunkOrigin::new(
GridPoint3::new(
4.into(),
8,
8,
192,
),
ROOT_RESOLUTION,
CHUNK_RESOLUTION,
);
let shared_points_iter = ChunkSharedPoints::new(chunk_origin, CHUNK_RESOLUTION);
let shared_points: Vec<GridPoint3> = shared_points_iter.collect();
assert_eq!(shared_points.len(), 9 * 9 * 64 - 7 * 7 * 64);
}
#[test]
fn all_shared_points_are_in_same_chunk() {
use globe::origin_of_chunk_in_same_root_containing;
const ROOT_RESOLUTION: [GridCoord; 2] = [16, 32];
const CHUNK_RESOLUTION: [GridCoord; 3] = [8, 8, 64];
let chunk_origin = ChunkOrigin::new(
GridPoint3::new(
4.into(),
8,
8,
192,
),
ROOT_RESOLUTION,
CHUNK_RESOLUTION,
);
let origins_of_shared_points_iter = ChunkSharedPoints::new(chunk_origin, CHUNK_RESOLUTION)
.map(|point| {
origin_of_chunk_in_same_root_containing(point, ROOT_RESOLUTION, CHUNK_RESOLUTION)
});
let origins: HashSet<ChunkOrigin> = origins_of_shared_points_iter.collect();
for origin in &origins {
assert_eq!(origin.pos().root.index, 4);
assert!(origin.pos().x >= chunk_origin.pos().x);
assert!(origin.pos().x <= chunk_origin.pos().x + CHUNK_RESOLUTION[0]);
assert!(origin.pos().y >= chunk_origin.pos().y);
assert!(origin.pos().y <= chunk_origin.pos().y + CHUNK_RESOLUTION[1]);
assert!(origin.pos().z >= chunk_origin.pos().z);
assert!(origin.pos().z < chunk_origin.pos().z + CHUNK_RESOLUTION[2]);
}
}
}