#![allow(dead_code)]
use std::collections::{HashMap, HashSet};
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct EdgeKey {
pub v0: u32,
pub v1: u32,
}
#[allow(dead_code)]
pub fn make_edge_key(a: u32, b: u32) -> EdgeKey {
if a <= b {
EdgeKey { v0: a, v1: b }
} else {
EdgeKey { v0: b, v1: a }
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct EdgeHashMap {
pub map: HashMap<EdgeKey, Vec<usize>>,
}
#[allow(dead_code)]
pub fn build_edge_hash_map(indices: &[u32]) -> EdgeHashMap {
let mut map: HashMap<EdgeKey, Vec<usize>> = HashMap::new();
let tri_count = indices.len() / 3;
for t in 0..tri_count {
let vs = [indices[t * 3], indices[t * 3 + 1], indices[t * 3 + 2]];
for k in 0..3 {
let key = make_edge_key(vs[k], vs[(k + 1) % 3]);
map.entry(key).or_default().push(t);
}
}
EdgeHashMap { map }
}
#[allow(dead_code)]
pub fn edge_count(ehm: &EdgeHashMap) -> usize {
ehm.map.len()
}
#[allow(dead_code)]
pub fn faces_for_edge(ehm: &EdgeHashMap, a: u32, b: u32) -> Option<&Vec<usize>> {
ehm.map.get(&make_edge_key(a, b))
}
#[allow(dead_code)]
pub fn edge_exists(ehm: &EdgeHashMap, a: u32, b: u32) -> bool {
ehm.map.contains_key(&make_edge_key(a, b))
}
#[allow(dead_code)]
pub fn boundary_edges(ehm: &EdgeHashMap) -> Vec<EdgeKey> {
ehm.map
.iter()
.filter(|(_, v)| v.len() == 1)
.map(|(k, _)| *k)
.collect()
}
#[allow(dead_code)]
pub fn non_manifold_edges(ehm: &EdgeHashMap) -> Vec<EdgeKey> {
ehm.map
.iter()
.filter(|(_, v)| v.len() > 2)
.map(|(k, _)| *k)
.collect()
}
#[allow(dead_code)]
pub fn unique_vertices(ehm: &EdgeHashMap) -> HashSet<u32> {
let mut set = HashSet::new();
for key in ehm.map.keys() {
set.insert(key.v0);
set.insert(key.v1);
}
set
}
#[allow(dead_code)]
pub fn edge_hash_to_json(ehm: &EdgeHashMap) -> String {
let boundary = boundary_edges(ehm).len();
format!(
"{{\"edge_count\":{},\"boundary_edges\":{}}}",
ehm.map.len(),
boundary,
)
}
#[cfg(test)]
mod tests {
use super::*;
fn single_tri() -> Vec<u32> {
vec![0, 1, 2]
}
fn two_tris() -> Vec<u32> {
vec![0, 1, 2, 1, 3, 2]
}
#[test]
fn test_make_edge_key_canonical() {
assert_eq!(make_edge_key(5, 3), make_edge_key(3, 5));
}
#[test]
fn test_build_single_tri() {
let ehm = build_edge_hash_map(&single_tri());
assert_eq!(edge_count(&ehm), 3);
}
#[test]
fn test_two_tris_edge_count() {
let ehm = build_edge_hash_map(&two_tris());
assert_eq!(edge_count(&ehm), 5);
}
#[test]
fn test_faces_for_edge() {
let ehm = build_edge_hash_map(&two_tris());
let faces = faces_for_edge(&ehm, 1, 2).expect("should succeed");
assert_eq!(faces.len(), 2);
}
#[test]
fn test_edge_exists() {
let ehm = build_edge_hash_map(&single_tri());
assert!(edge_exists(&ehm, 0, 1));
assert!(!edge_exists(&ehm, 0, 5));
}
#[test]
fn test_boundary_edges_single_tri() {
let ehm = build_edge_hash_map(&single_tri());
assert_eq!(boundary_edges(&ehm).len(), 3);
}
#[test]
fn test_boundary_edges_two_tris() {
let ehm = build_edge_hash_map(&two_tris());
assert_eq!(boundary_edges(&ehm).len(), 4);
}
#[test]
fn test_non_manifold_empty() {
let ehm = build_edge_hash_map(&two_tris());
assert!(non_manifold_edges(&ehm).is_empty());
}
#[test]
fn test_unique_vertices() {
let ehm = build_edge_hash_map(&two_tris());
assert_eq!(unique_vertices(&ehm).len(), 4);
}
#[test]
fn test_edge_hash_to_json() {
let ehm = build_edge_hash_map(&single_tri());
let json = edge_hash_to_json(&ehm);
assert!(json.contains("\"edge_count\":3"));
}
}