use itertools::Itertools;
use linear_isomorphic::{InnerSpace, RealField};
pub fn approx_normals<S, M, F, V>(vert_count: usize, face_iter: M) -> Vec<V>
where
M: Iterator<Item = F>,
F: Iterator<Item = (V, usize)>,
V: InnerSpace<S> + std::fmt::Debug,
S: RealField,
{
let mut res = vec![V::default(); vert_count];
let mut weights = vec![S::from(0.).unwrap(); vert_count];
for face in face_iter
{
let (verts, ids): (Vec<_>, Vec<_>) = face.unzip();
let mut id = 0;
for (&ref prev, &ref current, &ref next) in verts.iter().circular_tuple_windows()
{
let d1 = (prev.clone() - current.clone()).normalized();
let d2 = (next.clone() - current.clone()).normalized();
let mut n = d1.cross(&d2);
let mut weight = (d1.dot(&d2)).acos();
if !weight.is_finite()
{
weight = S::from(1).unwrap();
n[0] = S::from(1).unwrap();
n[1] = S::from(0).unwrap();
n[2] = S::from(0).unwrap();
}
res[ids[id]] = res[ids[id]].clone() + n;
weights[ids[id]] += weight;
id += 1;
}
}
for (i, w) in weights.iter().enumerate()
{
res[i] = res[i].clone() * (S::from(1.0).unwrap() / *w);
}
res
}