use slotmap::SlotMap;
use crate::ids::{FaceId, HalfEdgeId, VertexId};
#[derive(Debug, Clone)]
pub struct Vertex {
pub position: [f64; 3],
pub halfedge: Option<HalfEdgeId>,
}
#[derive(Debug, Clone)]
pub struct HalfEdge {
pub vertex: VertexId,
pub twin: Option<HalfEdgeId>,
pub next: Option<HalfEdgeId>,
pub prev: Option<HalfEdgeId>,
pub face: Option<FaceId>,
}
#[derive(Debug, Clone)]
pub struct Face {
pub halfedge: Option<HalfEdgeId>,
}
impl Vertex {
pub fn new(position: [f64; 3]) -> Self {
Self {
position,
halfedge: None,
}
}
}
impl Default for Vertex {
fn default() -> Self {
Self::new([0.0; 3])
}
}
impl HalfEdge {
pub fn new(vertex: VertexId) -> Self {
Self {
vertex,
twin: None,
next: None,
prev: None,
face: None,
}
}
}
impl Face {
pub fn new() -> Self {
Self { halfedge: None }
}
}
impl Default for Face {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct MeshStorage {
vertices: SlotMap<VertexId, Vertex>,
halfedges: SlotMap<HalfEdgeId, HalfEdge>,
faces: SlotMap<FaceId, Face>,
}
impl Default for MeshStorage {
fn default() -> Self {
Self::new()
}
}
impl MeshStorage {
pub fn new() -> Self {
Self {
vertices: SlotMap::with_key(),
halfedges: SlotMap::with_key(),
faces: SlotMap::with_key(),
}
}
pub fn add_vertex(&mut self, vertex: Vertex) -> VertexId {
self.vertices.insert(vertex)
}
pub fn add_halfedge(&mut self, halfedge: HalfEdge) -> HalfEdgeId {
self.halfedges.insert(halfedge)
}
pub fn add_face(&mut self, face: Face) -> FaceId {
self.faces.insert(face)
}
pub fn remove_vertex(&mut self, id: VertexId) -> Option<Vertex> {
self.vertices.remove(id)
}
pub fn remove_halfedge(&mut self, id: HalfEdgeId) -> Option<HalfEdge> {
self.halfedges.remove(id)
}
pub fn remove_face(&mut self, id: FaceId) -> Option<Face> {
self.faces.remove(id)
}
pub fn get_vertex(&self, id: VertexId) -> Option<&Vertex> {
self.vertices.get(id)
}
pub fn get_halfedge(&self, id: HalfEdgeId) -> Option<&HalfEdge> {
self.halfedges.get(id)
}
pub fn get_face(&self, id: FaceId) -> Option<&Face> {
self.faces.get(id)
}
pub fn get_vertex_mut(&mut self, id: VertexId) -> Option<&mut Vertex> {
self.vertices.get_mut(id)
}
pub fn get_halfedge_mut(&mut self, id: HalfEdgeId) -> Option<&mut HalfEdge> {
self.halfedges.get_mut(id)
}
pub fn get_face_mut(&mut self, id: FaceId) -> Option<&mut Face> {
self.faces.get_mut(id)
}
pub fn contains_vertex(&self, id: VertexId) -> bool {
self.vertices.contains_key(id)
}
pub fn contains_halfedge(&self, id: HalfEdgeId) -> bool {
self.halfedges.contains_key(id)
}
pub fn contains_face(&self, id: FaceId) -> bool {
self.faces.contains_key(id)
}
pub fn vertex_count(&self) -> usize {
self.vertices.len()
}
pub fn halfedge_count(&self) -> usize {
self.halfedges.len()
}
pub fn face_count(&self) -> usize {
self.faces.len()
}
pub fn vertex_ids(&self) -> impl Iterator<Item = VertexId> + '_ {
self.vertices.keys()
}
pub fn halfedge_ids(&self) -> impl Iterator<Item = HalfEdgeId> + '_ {
self.halfedges.keys()
}
pub fn face_ids(&self) -> impl Iterator<Item = FaceId> + '_ {
self.faces.keys()
}
pub fn vertices(&self) -> impl Iterator<Item = &Vertex> + '_ {
self.vertices.values()
}
pub fn vertices_mut(&mut self) -> impl Iterator<Item = &mut Vertex> + '_ {
self.vertices.values_mut()
}
pub fn halfedges(&self) -> impl Iterator<Item = &HalfEdge> + '_ {
self.halfedges.values()
}
pub fn halfedges_mut(&mut self) -> impl Iterator<Item = &mut HalfEdge> + '_ {
self.halfedges.values_mut()
}
pub fn faces(&self) -> impl Iterator<Item = &Face> + '_ {
self.faces.values()
}
pub fn faces_mut(&mut self) -> impl Iterator<Item = &mut Face> + '_ {
self.faces.values_mut()
}
pub fn is_empty(&self) -> bool {
self.vertex_count() == 0 && self.face_count() == 0
}
pub fn euler_characteristic(&self) -> i64 {
let v = self.vertex_count() as i64;
let e = (self.halfedge_count() / 2) as i64;
let f = self.face_count() as i64;
v - e + f
}
pub fn genus(&self) -> i64 {
(2 - self.euler_characteristic()) / 2
}
pub fn clear(&mut self) {
self.vertices.clear();
self.halfedges.clear();
self.faces.clear();
}
pub fn reserve(&mut self, vertex_cap: usize, halfedge_cap: usize, face_cap: usize) {
self.vertices.reserve(vertex_cap);
self.halfedges.reserve(halfedge_cap);
self.faces.reserve(face_cap);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn add_and_get_vertex() {
let mut mesh = MeshStorage::new();
let id = mesh.add_vertex(Vertex::new([1.0, 2.0, 3.0]));
assert!(mesh.contains_vertex(id));
let v = mesh.get_vertex(id).expect("刚插入的顶点必须可查");
assert_eq!(v.position, [1.0, 2.0, 3.0]);
assert!(v.halfedge.is_none());
assert_eq!(mesh.vertex_count(), 1);
}
#[test]
fn add_and_get_halfedge() {
let mut mesh = MeshStorage::new();
let v0 = mesh.add_vertex(Vertex::new([0.0; 3]));
let v1 = mesh.add_vertex(Vertex::new([1.0, 0.0, 0.0]));
let he = mesh.add_halfedge(HalfEdge::new(v1));
mesh.get_vertex_mut(v0).unwrap().halfedge = Some(he);
assert!(mesh.contains_halfedge(he));
let h = mesh.get_halfedge(he).unwrap();
assert_eq!(h.vertex, v1);
assert!(h.twin.is_none());
assert_eq!(mesh.get_vertex(v0).unwrap().halfedge, Some(he));
assert_eq!(mesh.halfedge_count(), 1);
}
#[test]
fn add_and_get_face() {
let mut mesh = MeshStorage::new();
let f = mesh.add_face(Face::new());
assert!(mesh.contains_face(f));
assert!(mesh.get_face(f).unwrap().halfedge.is_none());
assert_eq!(mesh.face_count(), 1);
}
#[test]
fn remove_vertex_invalidates_id() {
let mut mesh = MeshStorage::new();
let id = mesh.add_vertex(Vertex::new([0.0; 3]));
assert!(mesh.contains_vertex(id));
let removed = mesh.remove_vertex(id);
assert!(removed.is_some(), "删除已存在的顶点应返回 Some");
assert_eq!(removed.unwrap().position, [0.0; 3]);
assert!(!mesh.contains_vertex(id));
assert!(mesh.get_vertex(id).is_none());
assert_eq!(mesh.vertex_count(), 0);
assert!(mesh.remove_vertex(id).is_none());
}
#[test]
fn remove_halfedge_invalidates_id() {
let mut mesh = MeshStorage::new();
let v = mesh.add_vertex(Vertex::new([0.0; 3]));
let id = mesh.add_halfedge(HalfEdge::new(v));
assert!(mesh.remove_halfedge(id).is_some());
assert!(!mesh.contains_halfedge(id));
assert!(mesh.get_halfedge(id).is_none());
assert!(mesh.remove_halfedge(id).is_none());
}
#[test]
fn remove_face_invalidates_id() {
let mut mesh = MeshStorage::new();
let id = mesh.add_face(Face::new());
assert!(mesh.remove_face(id).is_some());
assert!(!mesh.contains_face(id));
assert!(mesh.get_face(id).is_none());
assert!(mesh.remove_face(id).is_none());
}
#[test]
fn slot_reuse_does_not_resurrect_old_id() {
let mut mesh = MeshStorage::new();
let old_id = mesh.add_vertex(Vertex::new([1.0, 1.0, 1.0]));
mesh.remove_vertex(old_id);
let new_id = mesh.add_vertex(Vertex::new([2.0, 2.0, 2.0]));
assert!(mesh.contains_vertex(new_id));
assert!(!mesh.contains_vertex(old_id));
assert!(mesh.get_vertex(old_id).is_none());
assert_ne!(old_id, new_id);
}
#[test]
fn get_mut_allows_in_place_update() {
let mut mesh = MeshStorage::new();
let v0 = mesh.add_vertex(Vertex::new([0.0; 3]));
let v1 = mesh.add_vertex(Vertex::new([1.0, 0.0, 0.0]));
let he = mesh.add_halfedge(HalfEdge::new(v1));
let h = mesh.get_halfedge_mut(he).unwrap();
h.twin = Some(he); h.next = Some(he);
h.prev = Some(he);
let v = mesh.get_vertex_mut(v0).unwrap();
v.halfedge = Some(he);
assert_eq!(mesh.get_vertex(v0).unwrap().halfedge, Some(he));
let h2 = mesh.get_halfedge(he).unwrap();
assert_eq!(h2.twin, Some(he));
assert_eq!(h2.next, Some(he));
assert_eq!(h2.prev, Some(he));
}
#[test]
fn accessing_invalid_id_never_panics() {
let mut mesh = MeshStorage::new();
let id = mesh.add_face(Face::new());
mesh.remove_face(id);
assert!(mesh.get_face(id).is_none());
assert!(mesh.get_face_mut(id).is_none());
assert!(!mesh.contains_face(id));
}
#[test]
fn clear_empties_all_three_slotmaps() {
let mut mesh = MeshStorage::new();
mesh.add_vertex(Vertex::new([1.0, 2.0, 3.0]));
mesh.add_vertex(Vertex::new([4.0, 5.0, 6.0]));
let v = mesh.add_vertex(Vertex::new([0.0; 3]));
mesh.add_halfedge(HalfEdge::new(v));
mesh.add_halfedge(HalfEdge::new(v));
mesh.add_face(Face::new());
assert_eq!(mesh.vertex_count(), 3);
assert_eq!(mesh.halfedge_count(), 2);
assert_eq!(mesh.face_count(), 1);
mesh.clear();
assert_eq!(mesh.vertex_count(), 0);
assert_eq!(mesh.halfedge_count(), 0);
assert_eq!(mesh.face_count(), 0);
assert_eq!(mesh.vertex_ids().count(), 0);
assert_eq!(mesh.halfedge_ids().count(), 0);
assert_eq!(mesh.face_ids().count(), 0);
assert_eq!(mesh.euler_characteristic(), 0);
}
#[test]
fn clear_equivalent_to_new() {
let mut mesh = MeshStorage::new();
mesh.add_vertex(Vertex::new([1.0; 3]));
mesh.add_face(Face::new());
mesh.clear();
let fresh = MeshStorage::new();
assert_eq!(mesh.vertex_count(), fresh.vertex_count());
assert_eq!(mesh.halfedge_count(), fresh.halfedge_count());
assert_eq!(mesh.face_count(), fresh.face_count());
}
#[test]
fn clear_allows_reuse_after() {
let mut mesh = MeshStorage::new();
mesh.add_vertex(Vertex::new([1.0; 3]));
mesh.clear();
let v = mesh.add_vertex(Vertex::new([2.0; 3]));
assert!(mesh.contains_vertex(v));
assert_eq!(mesh.vertex_count(), 1);
}
#[test]
fn reserve_does_not_change_counts() {
let mut mesh = MeshStorage::new();
mesh.add_vertex(Vertex::new([0.0; 3]));
mesh.reserve(100, 200, 50);
assert_eq!(mesh.vertex_count(), 1);
assert_eq!(mesh.halfedge_count(), 0);
assert_eq!(mesh.face_count(), 0);
}
#[test]
fn reserve_zero_is_noop() {
let mut mesh = MeshStorage::new();
mesh.reserve(0, 0, 0);
assert_eq!(mesh.vertex_count(), 0);
}
#[test]
fn is_empty_on_new_mesh() {
let mesh = MeshStorage::new();
assert!(mesh.is_empty());
}
#[test]
fn is_empty_after_clear() {
let mut mesh = MeshStorage::new();
mesh.add_vertex(Vertex::new([0.0; 3]));
mesh.add_face(Face::new());
assert!(!mesh.is_empty());
mesh.clear();
assert!(mesh.is_empty());
}
#[test]
fn vertices_iter_yields_all_data() {
let mut mesh = MeshStorage::new();
let _v0 = mesh.add_vertex(Vertex::new([1.0, 0.0, 0.0]));
let _v1 = mesh.add_vertex(Vertex::new([0.0, 1.0, 0.0]));
let _v2 = mesh.add_vertex(Vertex::new([0.0, 0.0, 1.0]));
let verts: Vec<&Vertex> = mesh.vertices().collect();
assert_eq!(verts.len(), 3);
let positions: Vec<[f64; 3]> = verts.iter().map(|v| v.position).collect();
assert!(positions.contains(&[1.0, 0.0, 0.0]));
assert!(positions.contains(&[0.0, 1.0, 0.0]));
assert!(positions.contains(&[0.0, 0.0, 1.0]));
assert_eq!(mesh.vertices().count(), mesh.vertex_ids().count());
}
#[test]
fn vertices_mut_allows_modification() {
let mut mesh = MeshStorage::new();
mesh.add_vertex(Vertex::new([1.0; 3]));
mesh.add_vertex(Vertex::new([2.0; 3]));
for v in mesh.vertices_mut() {
v.position = [0.0; 3];
}
for v in mesh.vertices() {
assert_eq!(v.position, [0.0; 3]);
}
}
#[test]
fn halfedges_faces_iters_match_id_counts() {
use crate::test_util::build_icosphere;
let mesh = build_icosphere(1);
assert_eq!(mesh.halfedges().count(), mesh.halfedge_ids().count());
assert_eq!(mesh.faces().count(), mesh.face_ids().count());
assert!(!mesh.is_empty());
}
#[test]
fn empty_iterators_yield_nothing() {
let mesh = MeshStorage::new();
assert_eq!(mesh.vertices().count(), 0);
assert_eq!(mesh.halfedges().count(), 0);
assert_eq!(mesh.faces().count(), 0);
}
}