use crate::shared::validate::LabelledEntry;
use std::collections::{HashMap, HashSet};
pub(super) fn local_step_per_corner(
by_idx: &HashMap<usize, &LabelledEntry>,
by_grid: &HashMap<(i32, i32), usize>,
) -> HashMap<usize, f32> {
let mut out = HashMap::with_capacity(by_idx.len());
for (&idx, entry) in by_idx {
let (i, j) = entry.grid;
let here = entry.pixel;
let i_step = match (
by_grid
.get(&(i - 1, j))
.and_then(|k| by_idx.get(k))
.map(|e| e.pixel),
by_grid
.get(&(i + 1, j))
.and_then(|k| by_idx.get(k))
.map(|e| e.pixel),
) {
(Some(l), Some(r)) => Some((r - l).norm() * 0.5),
(Some(l), None) => Some((here - l).norm()),
(None, Some(r)) => Some((r - here).norm()),
(None, None) => None,
};
let j_step = match (
by_grid
.get(&(i, j - 1))
.and_then(|k| by_idx.get(k))
.map(|e| e.pixel),
by_grid
.get(&(i, j + 1))
.and_then(|k| by_idx.get(k))
.map(|e| e.pixel),
) {
(Some(u), Some(d)) => Some((d - u).norm() * 0.5),
(Some(u), None) => Some((here - u).norm()),
(None, Some(d)) => Some((d - here).norm()),
(None, None) => None,
};
let step = match (i_step, j_step) {
(Some(a), Some(b)) => Some((a + b) * 0.5),
(Some(a), None) | (None, Some(a)) => Some(a),
(None, None) => None,
};
if let Some(s) = step {
if s.is_finite() && s > 0.0 {
out.insert(idx, s);
}
}
}
out
}
pub(super) fn flag_step_deviations(
local_steps: &HashMap<usize, f32>,
deviation_thresh_rel: f32,
) -> HashSet<usize> {
if deviation_thresh_rel <= 0.0 || local_steps.len() < 3 {
return HashSet::new();
}
let mut steps: Vec<f32> = local_steps.values().copied().collect();
steps.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
let median = steps[steps.len() / 2];
if median <= 0.0 || !median.is_finite() {
return HashSet::new();
}
let lo = median / (1.0 + deviation_thresh_rel);
let hi = median * (1.0 + deviation_thresh_rel);
local_steps
.iter()
.filter_map(|(&idx, &s)| if s < lo || s > hi { Some(idx) } else { None })
.collect()
}