use bevy_transform::components::Transform;
use glam::Vec3;
use bevy_utils::hashbrown::HashSet;
use itertools::Itertools;
use slotmap::SecondaryMap;
use crate::mesh::attributes::{AttributeKind, TraversalQueries};
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.halfedge();
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.halfedge())
.unwrap_or_else(|| edge_points.get(i.next().halfedge()).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.halfedge())
.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);
}
}
}
pub fn invert_normals(mesh: &mut HalfEdgeMesh) {
for face in mesh.faces.keys() {
let edges = mesh
.goto(face)
.iter_loop()
.map(|t| t.halfedge())
.collect::<StackVec<_>>();
let mut last_twin = mesh.halfedges[*edges.first().unwrap()].twin;
for (&from, &to) in edges.iter().circular_tuple_windows() {
mesh.halfedges[to].next = from;
let tmp = mesh.halfedges[to].twin;
mesh.halfedges[to].twin = last_twin;
mesh.halfedges[last_twin].twin = to;
last_twin = tmp;
}
}
}