use std::{collections::BTreeMap, ops::Bound};
use crate::zzbase::ZZNum;
#[derive(Debug, Clone)]
pub struct UnitSquareGrid {
num_points: usize,
cols_rows: BTreeMap<i64, BTreeMap<i64, Vec<usize>>>,
}
impl UnitSquareGrid {
pub fn cell_of<T: ZZNum>(zz: T) -> (i64, i64) {
let c = zz.complex64();
(c.re.round() as i64, c.im.round() as i64)
}
pub fn neighborhood_of<T: ZZNum>(zz: T) -> Vec<(i64, i64)> {
let c @ (x, y) = Self::cell_of(zz);
let r = (x + 1, y);
let l = (x - 1, y);
let u = (x, y + 1);
let d = (x, y - 1);
vec![l, d, c, u, r] }
pub fn seg_neighborhood_of<T: ZZNum>(p1: T, p2: T) -> Vec<(i64, i64)> {
let mut result = Self::neighborhood_of(p1);
result.extend(Self::neighborhood_of(p2));
result.sort();
result.dedup();
result
}
pub fn new() -> Self {
Self {
num_points: 0,
cols_rows: BTreeMap::new(),
}
}
pub fn add(&mut self, (x, y): (i64, i64), value: usize) {
self.num_points += 1;
self.cols_rows
.entry(x)
.or_default()
.entry(y)
.or_default()
.push(value);
}
pub fn get(&self, (x, y): (i64, i64)) -> Vec<usize> {
match self.cols_rows.get(&x) {
None => vec![],
Some(col) => match col.get(&y) {
None => vec![],
Some(vals) => vals.clone(),
},
}
}
pub fn get_cells(&self, cells: &[(i64, i64)]) -> Vec<usize> {
let mut pt_indices: Vec<usize> = Vec::new();
for cell in cells {
pt_indices.extend(self.get(*cell));
}
pt_indices
}
pub fn get_range(
&self,
x_range: (Bound<i64>, Bound<i64>),
y_range: (Bound<i64>, Bound<i64>),
) -> Vec<usize> {
let mut pt_indices: Vec<usize> = Vec::new();
for (_, col) in self.cols_rows.range(x_range) {
for (_, cell) in col.range(y_range) {
pt_indices.extend(cell);
}
}
pt_indices
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::zz::ZZ12;
use crate::zzbase::ZZBase;
use num_traits::{One, Zero};
#[test]
fn test_cell_of() {
assert_eq!(UnitSquareGrid::cell_of(ZZ12::zero()), (0, 0));
assert_eq!(UnitSquareGrid::cell_of(ZZ12::unit(0)), (1, 0));
assert_eq!(UnitSquareGrid::cell_of(ZZ12::unit(1)), (1, 1));
assert_eq!(UnitSquareGrid::cell_of(ZZ12::unit(2)), (1, 1));
assert_eq!(UnitSquareGrid::cell_of(ZZ12::unit(3)), (0, 1));
assert_eq!(UnitSquareGrid::cell_of(ZZ12::unit(4)), (-1, 1));
assert_eq!(UnitSquareGrid::cell_of(ZZ12::unit(5)), (-1, 1));
assert_eq!(UnitSquareGrid::cell_of(ZZ12::unit(6)), (-1, 0));
assert_eq!(UnitSquareGrid::cell_of(ZZ12::unit(7)), (-1, -1));
assert_eq!(UnitSquareGrid::cell_of(ZZ12::unit(8)), (-1, -1));
assert_eq!(UnitSquareGrid::cell_of(ZZ12::unit(9)), (0, -1));
assert_eq!(UnitSquareGrid::cell_of(ZZ12::unit(10)), (1, -1));
assert_eq!(UnitSquareGrid::cell_of(ZZ12::unit(11)), (1, -1));
}
#[test]
fn test_seg_neighborhood_of() {
let tmp1 = (ZZ12::one().scale(2) - ZZ12::unit(2) - ZZ12::unit(-1).scale(2)) * ZZ12::unit(1);
let tmp2 = (ZZ12::one().scale(3) - ZZ12::unit(2) - ZZ12::unit(-1).scale(3)) * ZZ12::unit(2);
let p1 = (tmp1 - tmp2) * ZZ12::unit(-2);
let p2 = p1 + ZZ12::unit(2);
let n0 = UnitSquareGrid::seg_neighborhood_of(p1, p2);
let n0_exp = &[(-1, 0), (0, -1), (0, 0), (0, 1), (1, 0)];
assert_eq!(n0, n0_exp);
let n1 = UnitSquareGrid::seg_neighborhood_of(ZZ12::zero(), ZZ12::unit(0));
let n1_exp = &[
(-1, 0),
(0, -1),
(0, 0),
(0, 1),
(1, -1),
(1, 0),
(1, 1),
(2, 0),
];
assert_eq!(n1, n1_exp);
let n2 = UnitSquareGrid::seg_neighborhood_of(ZZ12::zero(), ZZ12::unit(3));
let n2_exp = &[
(-1, 0),
(-1, 1),
(0, -1),
(0, 0),
(0, 1),
(0, 2),
(1, 0),
(1, 1),
];
assert_eq!(n2, n2_exp);
let n3 = UnitSquareGrid::seg_neighborhood_of(ZZ12::zero(), ZZ12::unit(1));
let n3_exp = &[
(-1, 0),
(0, -1),
(0, 0),
(0, 1),
(1, 0),
(1, 1),
(1, 2),
(2, 1),
];
assert_eq!(n3, n3_exp);
}
#[test]
fn test_indices_from_cells() {
let mut grid = UnitSquareGrid::new();
grid.add((0, 0), 0);
grid.add((0, 0), 1);
grid.add((1, 0), 2);
grid.add((1, 0), 0);
assert_eq!(grid.get_cells(&[(0, 0)]), &[0, 1]);
assert_eq!(grid.get_cells(&[(1, 0)]), &[2, 0]);
assert_eq!(UnitSquareGrid::get_cells(&grid, &[(2, 0)]), &[]);
assert_eq!(
UnitSquareGrid::get_cells(&grid, &[(2, 0), (1, 0), (0, 0)]),
&[2, 0, 0, 1]
);
}
}