use std::slice;
use arrayvec;
use super::{GridCoord, GridPoint2, GridPoint3, Root};
use super::ROOTS;
enum EquivalentPointsImpl {
NorthPole(NorthPolePoints),
SouthPole(SouthPolePoints),
EastArctic(EastArcticPoints),
WestArctic(WestArcticPoints),
EastTropics(EastTropicsPoints),
WestTropics(WestTropicsPoints),
EastAntarctic(EastAntarcticPoints),
WestAntarctic(WestAntarcticPoints),
Interior(InteriorPoints),
}
pub struct EquivalentPoints {
iter: EquivalentPointsImpl,
}
impl EquivalentPoints {
pub fn new(point: GridPoint3, root_resolution: [GridCoord; 2]) -> EquivalentPoints {
if point.x == 0 && point.y == 0 {
EquivalentPoints { iter: EquivalentPointsImpl::NorthPole(NorthPolePoints::new(point)) }
} else if point.x == root_resolution[0] && point.y == root_resolution[1] {
EquivalentPoints {
iter: EquivalentPointsImpl::SouthPole(SouthPolePoints::new(point, root_resolution)),
}
} else if point.x == 0 && point.y < root_resolution[0] {
EquivalentPoints {
iter: EquivalentPointsImpl::EastArctic(EastArcticPoints::new(point)),
}
} else if point.y == 0 {
EquivalentPoints {
iter: EquivalentPointsImpl::WestArctic(WestArcticPoints::new(point)),
}
} else if point.x == 0 && point.y >= root_resolution[0] {
EquivalentPoints {
iter: EquivalentPointsImpl::EastTropics(
EastTropicsPoints::new(point, root_resolution),
),
}
} else if point.x == root_resolution[0] && point.y < root_resolution[0] {
EquivalentPoints {
iter: EquivalentPointsImpl::WestTropics(
WestTropicsPoints::new(point, root_resolution),
),
}
} else if point.y == root_resolution[1] {
EquivalentPoints {
iter: EquivalentPointsImpl::EastAntarctic(
EastAntarcticPoints::new(point, root_resolution),
),
}
} else if point.x == root_resolution[0] && point.y >= root_resolution[0] {
EquivalentPoints {
iter: EquivalentPointsImpl::WestAntarctic(
WestAntarcticPoints::new(point, root_resolution),
),
}
} else {
EquivalentPoints { iter: EquivalentPointsImpl::Interior(InteriorPoints::new(point)) }
}
}
}
impl Iterator for EquivalentPoints {
type Item = GridPoint3;
fn next(&mut self) -> Option<GridPoint3> {
match &mut self.iter {
&mut EquivalentPointsImpl::NorthPole(ref mut iter) => iter.next(),
&mut EquivalentPointsImpl::SouthPole(ref mut iter) => iter.next(),
&mut EquivalentPointsImpl::EastArctic(ref mut iter) => iter.next(),
&mut EquivalentPointsImpl::WestArctic(ref mut iter) => iter.next(),
&mut EquivalentPointsImpl::EastTropics(ref mut iter) => iter.next(),
&mut EquivalentPointsImpl::WestTropics(ref mut iter) => iter.next(),
&mut EquivalentPointsImpl::EastAntarctic(ref mut iter) => iter.next(),
&mut EquivalentPointsImpl::WestAntarctic(ref mut iter) => iter.next(),
&mut EquivalentPointsImpl::Interior(ref mut iter) => iter.next(),
}
}
}
struct NorthPolePoints {
z: GridCoord,
roots_iter: slice::Iter<'static, Root>,
}
impl NorthPolePoints {
fn new(point: GridPoint3) -> NorthPolePoints {
NorthPolePoints {
z: point.z,
roots_iter: ROOTS.iter(),
}
}
}
impl Iterator for NorthPolePoints {
type Item = GridPoint3;
fn next(&mut self) -> Option<GridPoint3> {
self.roots_iter.next().map(|root| {
GridPoint3 {
rxy: GridPoint2 {
root: *root,
x: 0,
y: 0,
},
z: self.z,
}
})
}
}
struct SouthPolePoints {
x: GridCoord,
y: GridCoord,
z: GridCoord,
roots_iter: slice::Iter<'static, Root>,
}
impl SouthPolePoints {
fn new(point: GridPoint3, root_resolution: [GridCoord; 2]) -> SouthPolePoints {
SouthPolePoints {
x: root_resolution[0],
y: root_resolution[1],
z: point.z,
roots_iter: ROOTS.iter(),
}
}
}
impl Iterator for SouthPolePoints {
type Item = GridPoint3;
fn next(&mut self) -> Option<GridPoint3> {
self.roots_iter.next().map(|root| {
GridPoint3 {
rxy: GridPoint2 {
root: *root,
x: self.x,
y: self.y,
},
z: self.z,
}
})
}
}
struct EastArcticPoints {
points_iter: arrayvec::IntoIter<[GridPoint3; 2]>,
}
impl EastArcticPoints {
fn new(point: GridPoint3) -> EastArcticPoints {
use arrayvec::ArrayVec;
let mut points: ArrayVec<[GridPoint3; 2]> = ArrayVec::new();
points.push(point);
points.push(GridPoint3::new(
point.root.next_east(),
point.y,
0,
point.z,
));
EastArcticPoints { points_iter: points.into_iter() }
}
}
impl Iterator for EastArcticPoints {
type Item = GridPoint3;
fn next(&mut self) -> Option<GridPoint3> {
self.points_iter.next()
}
}
struct WestArcticPoints {
points_iter: arrayvec::IntoIter<[GridPoint3; 2]>,
}
impl WestArcticPoints {
fn new(point: GridPoint3) -> WestArcticPoints {
use arrayvec::ArrayVec;
let mut points: ArrayVec<[GridPoint3; 2]> = ArrayVec::new();
points.push(point);
points.push(GridPoint3::new(
point.root.next_west(),
0,
point.x,
point.z,
));
WestArcticPoints { points_iter: points.into_iter() }
}
}
impl Iterator for WestArcticPoints {
type Item = GridPoint3;
fn next(&mut self) -> Option<GridPoint3> {
self.points_iter.next()
}
}
struct EastTropicsPoints {
points_iter: arrayvec::IntoIter<[GridPoint3; 2]>,
}
impl EastTropicsPoints {
fn new(point: GridPoint3, root_resolution: [GridCoord; 2]) -> EastTropicsPoints {
use arrayvec::ArrayVec;
let mut points: ArrayVec<[GridPoint3; 2]> = ArrayVec::new();
points.push(point);
points.push(GridPoint3::new(
point.root.next_east(),
root_resolution[0],
point.y - root_resolution[0],
point.z,
));
EastTropicsPoints { points_iter: points.into_iter() }
}
}
impl Iterator for EastTropicsPoints {
type Item = GridPoint3;
fn next(&mut self) -> Option<GridPoint3> {
self.points_iter.next()
}
}
struct WestTropicsPoints {
points_iter: arrayvec::IntoIter<[GridPoint3; 2]>,
}
impl WestTropicsPoints {
fn new(point: GridPoint3, root_resolution: [GridCoord; 2]) -> WestTropicsPoints {
use arrayvec::ArrayVec;
let mut points: ArrayVec<[GridPoint3; 2]> = ArrayVec::new();
points.push(point);
points.push(GridPoint3::new(
point.root.next_west(),
0,
point.y + root_resolution[0],
point.z,
));
WestTropicsPoints { points_iter: points.into_iter() }
}
}
impl Iterator for WestTropicsPoints {
type Item = GridPoint3;
fn next(&mut self) -> Option<GridPoint3> {
self.points_iter.next()
}
}
struct EastAntarcticPoints {
points_iter: arrayvec::IntoIter<[GridPoint3; 2]>,
}
impl EastAntarcticPoints {
fn new(point: GridPoint3, root_resolution: [GridCoord; 2]) -> EastAntarcticPoints {
use arrayvec::ArrayVec;
let mut points: ArrayVec<[GridPoint3; 2]> = ArrayVec::new();
points.push(point);
points.push(GridPoint3::new(
point.root.next_east(),
root_resolution[0],
point.x + root_resolution[0],
point.z,
));
EastAntarcticPoints { points_iter: points.into_iter() }
}
}
impl Iterator for EastAntarcticPoints {
type Item = GridPoint3;
fn next(&mut self) -> Option<GridPoint3> {
self.points_iter.next()
}
}
struct WestAntarcticPoints {
points_iter: arrayvec::IntoIter<[GridPoint3; 2]>,
}
impl WestAntarcticPoints {
fn new(point: GridPoint3, root_resolution: [GridCoord; 2]) -> WestAntarcticPoints {
use arrayvec::ArrayVec;
let mut points: ArrayVec<[GridPoint3; 2]> = ArrayVec::new();
points.push(point);
points.push(GridPoint3::new(
point.root.next_west(),
point.y - root_resolution[0],
root_resolution[1],
point.z,
));
WestAntarcticPoints { points_iter: points.into_iter() }
}
}
impl Iterator for WestAntarcticPoints {
type Item = GridPoint3;
fn next(&mut self) -> Option<GridPoint3> {
self.points_iter.next()
}
}
struct InteriorPoints {
points_iter: arrayvec::IntoIter<[GridPoint3; 1]>,
}
impl InteriorPoints {
fn new(point: GridPoint3) -> InteriorPoints {
use arrayvec::ArrayVec;
let mut points: ArrayVec<[GridPoint3; 1]> = ArrayVec::new();
points.push(point);
InteriorPoints { points_iter: points.into_iter() }
}
}
impl Iterator for InteriorPoints {
type Item = GridPoint3;
fn next(&mut self) -> Option<GridPoint3> {
self.points_iter.next()
}
}
#[cfg(test)]
mod tests {
use std::collections::HashSet;
use grid::semi_arbitrary_compare;
use super::*;
#[test]
fn points_equivalent_to_north_pole() {
const ROOT_RESOLUTION: [GridCoord; 2] = [8, 16];
let point = GridPoint3::new(
4.into(),
0,
0,
77,
);
let points_iter = EquivalentPoints::new(point, ROOT_RESOLUTION);
let mut equivalent_points: Vec<GridPoint3> = points_iter.collect();
equivalent_points.sort_by(semi_arbitrary_compare);
assert_eq!(equivalent_points.len(), 5);
assert!(
equivalent_points ==
vec![
GridPoint3 {
rxy: GridPoint2 {
root: Root { index: 0 },
x: 0,
y: 0,
},
z: 77,
},
GridPoint3 {
rxy: GridPoint2 {
root: Root { index: 1 },
x: 0,
y: 0,
},
z: 77,
},
GridPoint3 {
rxy: GridPoint2 {
root: Root { index: 2 },
x: 0,
y: 0,
},
z: 77,
},
GridPoint3 {
rxy: GridPoint2 {
root: Root { index: 3 },
x: 0,
y: 0,
},
z: 77,
},
GridPoint3 {
rxy: GridPoint2 {
root: Root { index: 4 },
x: 0,
y: 0,
},
z: 77,
},
]
);
}
#[test]
fn points_equivalent_to_south_pole() {
const ROOT_RESOLUTION: [GridCoord; 2] = [8, 16];
let point = GridPoint3::new(
4.into(),
ROOT_RESOLUTION[0],
ROOT_RESOLUTION[1],
77,
);
let points_iter = EquivalentPoints::new(point, ROOT_RESOLUTION);
let mut equivalent_points: Vec<GridPoint3> = points_iter.collect();
equivalent_points.sort_by(semi_arbitrary_compare);
assert_eq!(equivalent_points.len(), 5);
assert!(
equivalent_points ==
vec![
GridPoint3 {
rxy: GridPoint2 {
root: Root { index: 0 },
x: ROOT_RESOLUTION[0],
y: ROOT_RESOLUTION[1],
},
z: 77,
},
GridPoint3 {
rxy: GridPoint2 {
root: Root { index: 1 },
x: ROOT_RESOLUTION[0],
y: ROOT_RESOLUTION[1],
},
z: 77,
},
GridPoint3 {
rxy: GridPoint2 {
root: Root { index: 2 },
x: ROOT_RESOLUTION[0],
y: ROOT_RESOLUTION[1],
},
z: 77,
},
GridPoint3 {
rxy: GridPoint2 {
root: Root { index: 3 },
x: ROOT_RESOLUTION[0],
y: ROOT_RESOLUTION[1],
},
z: 77,
},
GridPoint3 {
rxy: GridPoint2 {
root: Root { index: 4 },
x: ROOT_RESOLUTION[0],
y: ROOT_RESOLUTION[1],
},
z: 77,
},
]
);
}
#[test]
fn points_equivalent_to_east_arctic() {
const ROOT_RESOLUTION: [GridCoord; 2] = [8, 16];
let point = GridPoint3::new(
3.into(),
0,
3,
77,
);
let points_iter = EquivalentPoints::new(point, ROOT_RESOLUTION);
let mut equivalent_points: Vec<GridPoint3> = points_iter.collect();
equivalent_points.sort_by(semi_arbitrary_compare);
assert_eq!(equivalent_points.len(), 2);
assert!(
equivalent_points ==
vec![
GridPoint3 {
rxy: GridPoint2 {
root: Root { index: 3 },
x: 0,
y: 3,
},
z: 77,
},
GridPoint3 {
rxy: GridPoint2 {
root: Root { index: 4 },
x: 3,
y: 0,
},
z: 77,
},
]
);
}
#[test]
fn points_equivalent_to_west_arctic() {
const ROOT_RESOLUTION: [GridCoord; 2] = [8, 16];
let point = GridPoint3::new(
3.into(),
3,
0,
77,
);
let points_iter = EquivalentPoints::new(point, ROOT_RESOLUTION);
let mut equivalent_points: Vec<GridPoint3> = points_iter.collect();
equivalent_points.sort_by(semi_arbitrary_compare);
assert_eq!(equivalent_points.len(), 2);
assert!(
equivalent_points ==
vec![
GridPoint3 {
rxy: GridPoint2 {
root: Root { index: 2 },
x: 0,
y: 3,
},
z: 77,
},
GridPoint3 {
rxy: GridPoint2 {
root: Root { index: 3 },
x: 3,
y: 0,
},
z: 77,
},
]
);
}
#[test]
fn points_equivalent_to_east_tropics() {
const ROOT_RESOLUTION: [GridCoord; 2] = [8, 16];
let point = GridPoint3::new(
3.into(),
0,
13,
77,
);
let points_iter = EquivalentPoints::new(point, ROOT_RESOLUTION);
let mut equivalent_points: Vec<GridPoint3> = points_iter.collect();
equivalent_points.sort_by(semi_arbitrary_compare);
assert_eq!(equivalent_points.len(), 2);
assert!(
equivalent_points ==
vec![
GridPoint3 {
rxy: GridPoint2 {
root: Root { index: 3 },
x: 0,
y: 13,
},
z: 77,
},
GridPoint3 {
rxy: GridPoint2 {
root: Root { index: 4 },
x: 8,
y: 5,
},
z: 77,
},
]
);
}
#[test]
fn points_equivalent_to_west_tropics() {
const ROOT_RESOLUTION: [GridCoord; 2] = [8, 16];
let point = GridPoint3::new(
3.into(),
8,
4,
77,
);
let points_iter = EquivalentPoints::new(point, ROOT_RESOLUTION);
let mut equivalent_points: Vec<GridPoint3> = points_iter.collect();
equivalent_points.sort_by(semi_arbitrary_compare);
assert_eq!(equivalent_points.len(), 2);
assert!(
equivalent_points ==
vec![
GridPoint3 {
rxy: GridPoint2 {
root: Root { index: 2 },
x: 0,
y: 12,
},
z: 77,
},
GridPoint3 {
rxy: GridPoint2 {
root: Root { index: 3 },
x: 8,
y: 4,
},
z: 77,
},
]
);
}
#[test]
fn points_equivalent_to_east_antarctic() {
const ROOT_RESOLUTION: [GridCoord; 2] = [8, 16];
let point = GridPoint3::new(
3.into(),
3,
16,
77,
);
let points_iter = EquivalentPoints::new(point, ROOT_RESOLUTION);
let mut equivalent_points: Vec<GridPoint3> = points_iter.collect();
equivalent_points.sort_by(semi_arbitrary_compare);
assert_eq!(equivalent_points.len(), 2);
assert!(
equivalent_points ==
vec![
GridPoint3 {
rxy: GridPoint2 {
root: Root { index: 3 },
x: 3,
y: 16,
},
z: 77,
},
GridPoint3 {
rxy: GridPoint2 {
root: Root { index: 4 },
x: 8,
y: 11,
},
z: 77,
},
]
);
}
#[test]
fn points_equivalent_to_west_antarctic() {
const ROOT_RESOLUTION: [GridCoord; 2] = [8, 16];
let point = GridPoint3::new(
4.into(),
8,
11,
77,
);
let points_iter = EquivalentPoints::new(point, ROOT_RESOLUTION);
let mut equivalent_points: Vec<GridPoint3> = points_iter.collect();
equivalent_points.sort_by(semi_arbitrary_compare);
assert_eq!(equivalent_points.len(), 2);
assert!(
equivalent_points ==
vec![
GridPoint3 {
rxy: GridPoint2 {
root: Root { index: 3 },
x: 3,
y: 16,
},
z: 77,
},
GridPoint3 {
rxy: GridPoint2 {
root: Root { index: 4 },
x: 8,
y: 11,
},
z: 77,
},
]
);
}
#[test]
fn points_equivalent_to_interior() {
const ROOT_RESOLUTION: [GridCoord; 2] = [8, 16];
let point = GridPoint3::new(
4.into(),
3,
5,
77,
);
let points_iter = EquivalentPoints::new(point, ROOT_RESOLUTION);
let mut equivalent_points: Vec<GridPoint3> = points_iter.collect();
equivalent_points.sort_by(semi_arbitrary_compare);
assert_eq!(equivalent_points.len(), 1);
assert!(
equivalent_points ==
vec![
GridPoint3 {
rxy: GridPoint2 {
root: Root { index: 4 },
x: 3,
y: 5,
},
z: 77,
},
]
);
}
#[test]
fn all_equivalent_points_symmetric() {
const ROOT_RESOLUTION: [GridCoord; 2] = [16, 32];
for xy in iproduct!(0..(ROOT_RESOLUTION[0] + 1), 0..(ROOT_RESOLUTION[1] + 1)) {
let (x, y) = xy;
let point = GridPoint3::new(
4.into(),
x,
y,
77,
);
let points_iter = EquivalentPoints::new(point, ROOT_RESOLUTION);
let equivalent_points: HashSet<GridPoint3> = points_iter.collect();
for point2 in &equivalent_points {
let points_iter2 = EquivalentPoints::new(*point2, ROOT_RESOLUTION);
let equivalent_points2: HashSet<GridPoint3> = points_iter2.collect();
assert_eq!(equivalent_points, equivalent_points2);
}
}
}
}