use nalgebra::{Point2, Vector2};
use std::collections::HashMap;
use super::LabelledNeighbour;
pub(crate) fn collect_labelled_neighbours(
pos: (i32, i32),
window_half: i32,
labelled: &HashMap<(i32, i32), usize>,
positions: &[Point2<f32>],
) -> Vec<LabelledNeighbour> {
let mut out = Vec::new();
for dj in -window_half..=window_half {
for di in -window_half..=window_half {
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(crate) fn predict_from_neighbours(
target: (i32, i32),
neighbours: &[LabelledNeighbour],
u: Vector2<f32>,
v: Vector2<f32>,
cell_size: f32,
labelled: &HashMap<(i32, i32), usize>,
positions: &[Point2<f32>],
) -> Point2<f32> {
debug_assert!(!neighbours.is_empty());
let global_i_step = u * cell_size;
let global_j_step = v * cell_size;
let mut sum_x = 0.0_f32;
let mut sum_y = 0.0_f32;
let mut sum_w = 0.0_f32;
for n in neighbours {
let di = (target.0 - n.at.0) as f32;
let dj = (target.1 - n.at.1) as f32;
let d2 = di * di + dj * dj;
let w = if d2 > 0.0 { 1.0 / d2 } else { 1.0 };
let i_step = local_step_at(n.at, (1, 0), labelled, positions).unwrap_or(global_i_step);
let j_step = local_step_at(n.at, (0, 1), labelled, positions).unwrap_or(global_j_step);
let off = i_step * di + j_step * dj;
sum_x += w * (n.position.x + off.x);
sum_y += w * (n.position.y + off.y);
sum_w += w;
}
Point2::new(sum_x / sum_w, sum_y / sum_w)
}
pub(crate) fn is_extrapolating(target: (i32, i32), neighbours: &[LabelledNeighbour]) -> bool {
let mut has_neg_di = false;
let mut has_pos_di = false;
let mut has_neg_dj = false;
let mut has_pos_dj = false;
for n in neighbours {
let di = target.0 - n.at.0;
let dj = target.1 - n.at.1;
if di > 0 {
has_neg_di = true; } else if di < 0 {
has_pos_di = true;
}
if dj > 0 {
has_neg_dj = true;
} else if dj < 0 {
has_pos_dj = true;
}
}
!(has_neg_di && has_pos_di && has_neg_dj && has_pos_dj)
}
fn local_step_at(
at: (i32, i32),
step: (i32, i32),
labelled: &HashMap<(i32, i32), usize>,
positions: &[Point2<f32>],
) -> Option<Vector2<f32>> {
let here = labelled.get(&at).map(|&i| positions[i])?;
let fwd = (at.0 + step.0, at.1 + step.1);
let bwd = (at.0 - step.0, at.1 - step.1);
let fwd_pos = labelled.get(&fwd).map(|&i| positions[i]);
let bwd_pos = labelled.get(&bwd).map(|&i| positions[i]);
match (fwd_pos, bwd_pos) {
(Some(f), Some(b)) => {
let v = (f - b) * 0.5;
Some(v)
}
(Some(f), None) => Some(f - here),
(None, Some(b)) => Some(here - b),
(None, None) => None,
}
}