use bevy_transform::components::Transform;
use itertools::Itertools;
use super::{
attributes::SelectionQueries, Face, FaceId, HalfEdgeId, HalfEdgeMesh, StackVec, VertexId,
};
pub fn transform(mesh: &mut HalfEdgeMesh, face: FaceId, transform: Transform) {
let verticies = mesh
.goto(face)
.iter_loop()
.map(|e| e.vertex())
.collect::<StackVec<_>>();
let positions = mesh
.attributes
.get_mut(&super::attributes::AttributeKind::Positions)
.unwrap()
.as_vertices_vec3_mut();
for vertex in verticies {
positions.insert(vertex, transform.transform_point(positions[vertex]));
}
}
pub fn delete(mesh: &mut HalfEdgeMesh, face: FaceId) {
let r#loop: StackVec<_> = mesh.goto(face).iter_loop().map(|t| t.halfedge()).collect();
for edge in r#loop {
mesh[edge].face = None
}
mesh.faces.remove(face);
}
pub fn split(mesh: &mut HalfEdgeMesh, v: VertexId, w: VertexId) -> HalfEdgeId {
let v = mesh.goto(v);
if v.find_halfedge_to(w).is_some() {
panic!("Vertices {v:?} and {w:?} provided to split a face already share an edge");
}
let twin_next = v
.adjacent_faces()
.find(|p| p.iter_loop().contains(w))
.expect("Vertices provided to split a face must share a face.");
let face = twin_next.face().unwrap();
let edge_previous = twin_next.previous();
let edge_next = twin_next.iter_loop().find(|t| t.vertex() == w).unwrap();
let (edge, mut twin) = mesh.attach_edge(edge_previous.halfedge(), edge_next.halfedge());
let face_id = mesh.faces.insert(Face { halfedge: twin });
mesh[twin].face = Some(face_id);
mesh[edge].face = Some(face);
mesh[face].halfedge = edge;
twin = mesh[twin].next;
while mesh[twin].twin != edge {
mesh[twin].face = Some(face_id);
twin = mesh[twin].next;
}
edge
}
pub fn extrude(mesh: &mut HalfEdgeMesh, face: FaceId, length: f32) -> StackVec<FaceId> {
let shift = length * mesh.select(face).calculate_normal().unwrap();
let face_edges = mesh
.goto(face)
.iter_loop()
.map(|e| (e.halfedge(), e.vertex(), e.twin().halfedge()))
.collect::<StackVec<_>>();
let is_origin_twin_boundary = mesh
.goto(face)
.iter_loop()
.all(|e| e.twin().face().is_none());
for edge in &face_edges {
mesh[edge.0].face = None;
if is_origin_twin_boundary {
mesh[edge.2].face = Some(FaceId::default());
}
}
let new_verts = (0..face_edges.len())
.map(|_| mesh.new_vertex())
.collect::<StackVec<_>>();
let v = new_verts[0]; let new_faces = face_edges
.iter()
.zip(new_verts)
.circular_tuple_windows()
.map(|((&(_, v1, _), v2), (&(_, v3, _), v4))| {
let positions = mesh
.attributes
.get_mut(&super::attributes::AttributeKind::Positions)
.unwrap()
.as_vertices_vec3_mut();
positions.insert(v2, positions[v1] + shift);
mesh.new_face(&[v3, v4, v2, v1])
})
.collect::<StackVec<_>>();
let old_face_goes_here = mesh
.goto(v)
.iter_outgoing()
.find(|e| e.face().is_none())
.unwrap()
.iter_loop()
.map(|e| e.halfedge())
.collect::<StackVec<_>>();
mesh[face].halfedge = old_face_goes_here[0];
for edge in old_face_goes_here {
mesh[edge].face = Some(face);
}
if is_origin_twin_boundary {
for (_, _, boundary) in face_edges {
mesh[boundary].face = None;
}
}
new_faces
}
#[cfg(test)]
mod tests {
use slotmap::KeyData;
use smallvec::SmallVec;
use crate::mesh::{tests::sample_mesh, vertex_ops, FaceId, VertexId};
#[test]
fn test_delete() {
let mut mesh = sample_mesh();
super::delete(&mut mesh, FaceId(KeyData::from_ffi(1)));
assert!(!mesh.faces.contains_key(FaceId(KeyData::from_ffi(1))));
assert_eq!(mesh.count_face_edges(), 12);
assert_eq!(mesh.count_islands(), 1);
assert_eq!(mesh.vertex_degree(VertexId(KeyData::from_ffi(3))), 4);
assert_eq!(
mesh.goto(VertexId(KeyData::from_ffi(3)))
.adjacent_faces()
.count(),
3
);
assert_eq!(
mesh.goto(VertexId(KeyData::from_ffi(1)))
.adjacent_faces()
.count(),
0
);
}
#[test]
fn test_split() {
let mut mesh = sample_mesh();
let new_edge = super::split(
&mut mesh,
VertexId(KeyData::from_ffi(1)),
VertexId(KeyData::from_ffi(3)),
);
assert_eq!(mesh.count_islands(), 1);
assert_eq!(mesh.count_face_edges(), 18);
assert_eq!(mesh.face_count(), 5);
assert_eq!(mesh.vertex_degree(VertexId(KeyData::from_ffi(3))), 5);
assert_eq!(mesh[new_edge].face, Some(FaceId(KeyData::from_ffi(1))));
assert_eq!(
mesh[mesh[new_edge].twin].face,
Some(FaceId(KeyData::from_ffi(5)))
);
assert_eq!(
mesh.goto(FaceId(KeyData::from_ffi(1))).iter_loop().count(),
3
);
assert_eq!(
mesh.goto(FaceId(KeyData::from_ffi(5))).iter_loop().count(),
3
);
assert_eq!(
mesh.goto(FaceId(KeyData::from_ffi(2))).iter_loop().count(),
4
);
}
#[test]
fn test_extrude() {
let mut mesh = sample_mesh();
let v = mesh.vertex_keys().collect::<SmallVec<[_; 9]>>();
let face = vertex_ops::chamfer(&mut mesh, v[2], 0.25);
super::extrude(&mut mesh, face, 0.5);
assert_eq!(mesh.count_islands(), 1);
assert_eq!(mesh.count_face_edges(), 40);
assert_eq!(mesh.face_count(), 9);
}
}