use bevy::{prelude::{Transform, Vec3}, utils::hashbrown::HashSet};
use itertools::Itertools;
use slotmap::SecondaryMap;
use crate::mesh::attributes::{TraversalQueries, AttributeKind};
use super::{attributes::SelectionQueries, edge_ops, FaceId, HalfEdgeId, HalfEdgeMesh, StackVec, VertexId};
pub fn transform(mesh:&mut HalfEdgeMesh, transform:Transform) {
let positions = mesh.attributes.get_mut(&AttributeKind::Positions).unwrap().as_vertices_vec3_mut();
for (_, position) in positions.iter_mut() {
*position = transform.transform_point(*position);
}
}
pub fn subdivide(mesh:&mut HalfEdgeMesh) {
let mut face_points:SecondaryMap<FaceId, Vec3> = SecondaryMap::new();
let mut edge_points:SecondaryMap<HalfEdgeId, Vec3> = SecondaryMap::new();
let original_vertices = mesh.vertex_keys().collect::<HashSet<_>>();
for face in mesh.faces.keys() {
let fp = mesh.select(face).calculate_centroid();
face_points.insert(face, fp);
}
let mut split_vertices:HashSet<VertexId> = HashSet::new();
for edge in mesh.halfedges.keys().collect::<Vec<_>>() {
if !edge_points.contains_key(edge) {
let e = mesh.goto(edge);
let a = e.position();
let (m, n) = e.face().map(|f| (face_points[f], 1.0)).unwrap_or((Vec3::ZERO, 0.0));
let twin = e.twin();
let f = twin.position();
let (e, n2) = twin.face().map(|f| (face_points[f], 1.0)).unwrap_or((Vec3::ZERO, 0.0));
let twin = *twin;
let vertex = edge_ops::split(mesh, edge, 0.5);
split_vertices.insert(vertex);
edge_points.insert(edge, (a+f+m+e)/(n+n2+2.0));
edge_points.insert(twin, (a+f+m+e)/(n+n2+2.0));
mesh.attributes.get_mut(&AttributeKind::Positions).unwrap().as_vertices_vec3_mut().insert(vertex, (a+f+m+e)/4.0);
}
}
for &vertex in &original_vertices {
let p = mesh.goto(vertex).position();
let (sum, nf) = mesh.goto(vertex).adjacent_faces().fold((Vec3::ZERO, 0.0_f32), |acc, i| (acc.0 + face_points[i.face().unwrap()], acc.1+1.0));
let f = sum / nf;
let (sum, ne) = mesh.goto(vertex).iter_outgoing().fold((Vec3::ZERO, 0.0_f32), |acc, i| (acc.0 + *edge_points.get(*i).unwrap_or_else(|| edge_points.get(*i.next()).unwrap()), acc.1+1.0));
let r = sum / ne;
let n = nf.max(ne);
let new_position = (f+2.0*r+(n-3.0)*p)/n;
mesh.attributes.get_mut(&AttributeKind::Positions).unwrap().as_vertices_vec3_mut().insert(vertex, new_position);
}
for (face, face_point) in face_points {
let split_halfedge_start = if split_vertices.contains(&mesh.goto(face).vertex()) {
mesh.goto(face).halfedge()
} else {
mesh.goto(face).next().halfedge()
};
let face_vertex = mesh.new_vertex();
mesh.attributes.get_mut(&AttributeKind::Positions).unwrap().as_vertices_vec3_mut().insert(face_vertex, face_point);
for edge in mesh.goto(face).iter_loop().map(|t| *t).collect::<StackVec<_>>() {
mesh[edge].face = None;
}
mesh.faces.remove(face);
let tuples = mesh.goto(split_halfedge_start).iter_loop().map(|t| t.vertex()).tuples::<(VertexId, VertexId)>().collect::<StackVec<_>>();
for (&(split, original), &(split_next, _)) in tuples.iter().circular_tuple_windows() {
let new_face = [split, original, split_next, face_vertex];
mesh.new_face(&new_face);
}
}
}