use crate::shared::grow::{Admit, GrowResult, LabelledNeighbour, SquareAttachPolicy};
use nalgebra::Point2;
use std::collections::HashMap;
pub(super) enum TryCellResult {
NoCandidates,
Ambiguous,
PolicyRejected,
EdgeRejected,
Attached(usize),
}
pub(super) fn try_attach_at_cell<V: SquareAttachPolicy>(
cell: (i32, i32),
pred: Point2<f32>,
hits: &[(usize, f32)],
ambiguity_factor: f32,
grow: &GrowResult,
positions: &[Point2<f32>],
policy: &V,
) -> TryCellResult {
if hits.is_empty() {
return TryCellResult::NoCandidates;
}
if hits.len() >= 2 {
let d0 = hits[0].1.max(f32::EPSILON);
let d1 = hits[1].1;
if d1 / d0 < ambiguity_factor {
return TryCellResult::Ambiguous;
}
}
let candidate_idx = hits[0].0;
let neighbours = collect_labelled_neighbours(cell, &grow.labelled, positions);
if matches!(
policy.accept_candidate(candidate_idx, cell, pred, &neighbours),
Admit::Reject
) {
return TryCellResult::PolicyRejected;
}
if !any_cardinal_edge_ok(candidate_idx, cell, &grow.labelled, policy) {
return TryCellResult::EdgeRejected;
}
TryCellResult::Attached(candidate_idx)
}
pub(super) fn collect_labelled_neighbours(
pos: (i32, i32),
labelled: &HashMap<(i32, i32), usize>,
positions: &[Point2<f32>],
) -> Vec<LabelledNeighbour> {
let mut out = Vec::new();
for dj in -1..=1_i32 {
for di in -1..=1_i32 {
if di == 0 && dj == 0 {
continue;
}
let at = (pos.0 + di, pos.1 + dj);
if let Some(&idx) = labelled.get(&at) {
out.push(LabelledNeighbour {
idx,
at,
position: positions[idx],
});
}
}
}
out
}
pub(super) fn any_cardinal_edge_ok<V: SquareAttachPolicy>(
c_idx: usize,
pos: (i32, i32),
labelled: &HashMap<(i32, i32), usize>,
policy: &V,
) -> bool {
let mut found_any = false;
for (di, dj) in [(1, 0), (-1, 0), (0, 1), (0, -1)] {
let neigh = (pos.0 + di, pos.1 + dj);
if let Some(&n_idx) = labelled.get(&neigh) {
found_any = true;
if policy.edge_ok(c_idx, n_idx, pos, neigh) {
return true;
}
}
}
!found_any
}