use crate::topology::point::PointId;
use crate::topology::sieve::Sieve;
use crate::topology::sieve::strata::compute_strata;
type P = PointId;
#[derive(Clone, Copy, Debug)]
pub struct AdjacencyOpts {
pub max_down_depth: Option<u32>,
pub same_stratum_only: bool,
}
impl Default for AdjacencyOpts {
fn default() -> Self {
Self {
max_down_depth: Some(1),
same_stratum_only: true,
}
}
}
#[inline]
fn boundary_points<S>(sieve: &S, p: P, max_down_depth: Option<u32>) -> Vec<P>
where
S: Sieve<Point = P>,
{
use std::collections::{HashSet, VecDeque};
match max_down_depth {
Some(0) => Vec::new(),
Some(1) => {
let mut v: Vec<P> = sieve.cone_points(p).collect();
v.sort_unstable();
v.dedup();
v
}
Some(2) => {
let mut out = Vec::new();
let mut seen: HashSet<P> = HashSet::with_capacity(16);
let mut q: VecDeque<(P, u32)> = VecDeque::with_capacity(16);
q.extend(sieve.cone_points(p).map(|x| (x, 1)));
while let Some((r, d)) = q.pop_front() {
if seen.insert(r) {
out.push(r);
if d < 2 {
for s in sieve.cone_points(r) {
if !seen.contains(&s) {
q.push_back((s, d + 1));
}
}
}
}
}
out.sort_unstable();
out.dedup();
out
}
None | Some(_) => {
let limit = max_down_depth.unwrap_or(u32::MAX);
let mut out = Vec::new();
let mut seen: HashSet<P> = HashSet::with_capacity(64);
let mut q: VecDeque<(P, u32)> = VecDeque::with_capacity(64);
q.extend(sieve.cone_points(p).map(|x| (x, 1)));
while let Some((r, d)) = q.pop_front() {
if seen.insert(r) {
out.push(r);
if d < limit {
for s in sieve.cone_points(r) {
if !seen.contains(&s) {
q.push_back((s, d + 1));
}
}
}
}
}
out.sort_unstable();
out.dedup();
out
}
}
}
#[inline]
pub fn adjacent_with<S>(sieve: &S, p: P, opts: AdjacencyOpts) -> Vec<P>
where
S: Sieve<Point = P>,
{
use std::collections::HashSet;
let height_map = if opts.same_stratum_only {
compute_strata(sieve).ok().map(|cache| cache.height)
} else {
None
};
let seed_height = height_map.as_ref().and_then(|hm| hm.get(&p).copied());
let boundary = boundary_points(sieve, p, opts.max_down_depth);
let mut neigh = HashSet::new();
for b in boundary {
for (cell, _) in sieve.support(b) {
if cell == p {
continue;
}
if let (Some(hp), Some(hm)) = (seed_height, height_map.as_ref())
&& hm.get(&cell).copied() != Some(hp)
{
continue;
}
neigh.insert(cell);
}
}
let mut out: Vec<P> = neigh.into_iter().collect();
out.sort_unstable();
out
}
pub fn adjacent<S>(sieve: &S, p: P) -> Vec<P>
where
S: Sieve<Point = P>,
{
adjacent_with(sieve, p, AdjacencyOpts::default())
}