use std::collections::HashSet;
use ndarray::{Array2, ArrayBase, AsArray, Axis, Ix3, ViewRepr, Zip};
use crate::error::ImgalError;
use crate::traits::numeric::AsNumeric;
pub fn gs_mask<'a, T, A>(
data: A,
g_coords: &[f64],
s_coords: &[f64],
axis: Option<usize>,
) -> Result<Array2<bool>, ImgalError>
where
A: AsArray<'a, T, Ix3>,
T: 'a + AsNumeric,
{
let gl = g_coords.len();
let sl = s_coords.len();
if gl != sl {
return Err(ImgalError::MismatchedArrayLengths {
a_arr_name: "g_coords",
a_arr_len: gl,
b_arr_name: "s_coords",
b_arr_len: sl,
});
}
let a = axis.unwrap_or(2);
if a >= 3 {
return Err(ImgalError::InvalidAxis {
axis_idx: a,
dim_len: 3,
});
}
let view: ArrayBase<ViewRepr<&'a T>, Ix3> = data.into();
let mut coords_set: HashSet<(u64, u64)> = HashSet::with_capacity(gl);
g_coords.iter().zip(s_coords.iter()).for_each(|(g, s)| {
coords_set.insert((g.to_bits(), s.to_bits()));
});
let mut shape = view.shape().to_vec();
shape.remove(a);
let mut map_arr = Array2::<bool>::default((shape[0], shape[1]));
let lanes = view.lanes(Axis(a));
Zip::from(lanes)
.and(map_arr.view_mut())
.par_for_each(|ln, p| {
let dg = ln[0].to_f64();
let ds = ln[1].to_f64();
if !dg.is_nan() || !ds.is_nan() || dg != 0.0 && ds != 0.0 {
if coords_set.contains(&(dg.to_bits(), ds.to_bits())) {
*p = true;
}
}
});
Ok(map_arr)
}
pub fn gs_modulation(g: f64, s: f64) -> f64 {
let g_sqr: f64 = g * g;
let s_sqr: f64 = s * s;
f64::sqrt(g_sqr + s_sqr)
}
pub fn gs_phase(g: f64, s: f64) -> f64 {
s.atan2(g)
}
pub fn monoexponential_coords(tau: f64, omega: f64) -> (f64, f64) {
let denom = 1.0 + (omega * tau).powi(2);
let g = 1.0 / denom;
let s = (omega * tau) / denom;
(g, s)
}