use std::collections::{HashMap, HashSet};
#[allow(unused_imports)]
use super::functions::*;
use super::functions::{
fill_hole_ear_clipping, find_boundary_loops, fix_non_manifold_edges, merge_duplicate_vertices,
};
pub struct HalfEdge {
pub vertex: usize,
pub face: usize,
pub next: usize,
pub prev: usize,
pub twin: Option<usize>,
}
pub struct HalfEdgeMesh {
pub vertices: Vec<[f64; 3]>,
pub half_edges: Vec<HalfEdge>,
pub face_starts: Vec<usize>,
}
impl HalfEdgeMesh {
pub fn from_triangle_soup(vertices: Vec<[f64; 3]>, triangles: Vec<[usize; 3]>) -> Self {
let mut half_edges: Vec<HalfEdge> = Vec::new();
let mut face_starts: Vec<usize> = Vec::new();
let mut edge_map: HashMap<(usize, usize), usize> = HashMap::new();
for (face_idx, tri) in triangles.iter().enumerate() {
let base = half_edges.len();
face_starts.push(base);
for k in 0..3 {
let to_v = tri[(k + 1) % 3];
half_edges.push(HalfEdge {
vertex: to_v,
face: face_idx,
next: base + (k + 1) % 3,
prev: base + (k + 2) % 3,
twin: None,
});
edge_map.insert((tri[k], to_v), base + k);
}
}
let n = half_edges.len();
for i in 0..n {
if half_edges[i].twin.is_none() {
let prev_idx = half_edges[i].prev;
let from_v = half_edges[prev_idx].vertex;
let to_v = half_edges[i].vertex;
if let Some(&twin_idx) = edge_map.get(&(to_v, from_v)) {
half_edges[i].twin = Some(twin_idx);
half_edges[twin_idx].twin = Some(i);
}
}
}
HalfEdgeMesh {
vertices,
half_edges,
face_starts,
}
}
pub fn is_manifold(&self) -> bool {
let mut seen: HashMap<(usize, usize), usize> = HashMap::new();
for (i, he) in self.half_edges.iter().enumerate() {
let prev = &self.half_edges[he.prev];
let from_v = prev.vertex;
let to_v = he.vertex;
let count = seen.entry((from_v, to_v)).or_insert(0);
*count += 1;
if *count > 1 {
let _ = i;
return false;
}
}
true
}
pub fn boundary_edges(&self) -> Vec<usize> {
self.half_edges
.iter()
.enumerate()
.filter_map(|(i, he)| if he.twin.is_none() { Some(i) } else { None })
.collect()
}
pub fn vertex_valence(&self, v: usize) -> usize {
self.half_edges.iter().filter(|he| he.vertex == v).count()
}
pub fn face_count(&self) -> usize {
self.face_starts.len()
}
pub fn vertex_count(&self) -> usize {
self.vertices.len()
}
pub fn boundary_loops(&self) -> Vec<Vec<usize>> {
let boundary_hes = self.boundary_edges();
if boundary_hes.is_empty() {
return Vec::new();
}
let mut from_to_he: HashMap<usize, usize> = HashMap::new();
for &he_idx in &boundary_hes {
let prev_idx = self.half_edges[he_idx].prev;
let from_v = self.half_edges[prev_idx].vertex;
from_to_he.insert(from_v, he_idx);
}
let mut visited: HashSet<usize> = HashSet::new();
let mut loops = Vec::new();
for &start_he in &boundary_hes {
if visited.contains(&start_he) {
continue;
}
let mut loop_verts = Vec::new();
let mut current = start_he;
loop {
visited.insert(current);
let to_v = self.half_edges[current].vertex;
loop_verts.push(to_v);
match from_to_he.get(&to_v) {
Some(&next_he) if !visited.contains(&next_he) => {
current = next_he;
}
_ => break,
}
}
if loop_verts.len() >= 3 {
loops.push(loop_verts);
}
}
loops
}
}
pub struct MeshRepairReport {
pub n_degenerate_removed: usize,
pub n_holes_filled: usize,
pub n_duplicates_merged: usize,
pub n_normals_fixed: usize,
}
pub struct FlipMesh {
pub vertices: Vec<[f64; 3]>,
pub triangles: Vec<[usize; 3]>,
pub n_flips: usize,
}
impl FlipMesh {
pub fn new(vertices: Vec<[f64; 3]>, triangles: Vec<[usize; 3]>) -> Self {
Self {
vertices,
triangles,
n_flips: 0,
}
}
pub fn is_locally_delaunay(va: [f64; 3], vb: [f64; 3], vc: [f64; 3], vd: [f64; 3]) -> bool {
let ax = va[0] - vd[0];
let ay = va[1] - vd[1];
let bx = vb[0] - vd[0];
let by = vb[1] - vd[1];
let cx = vc[0] - vd[0];
let cy = vc[1] - vd[1];
let det = ax * (by * (cx * cx + cy * cy) - cy * (bx * bx + by * by))
- ay * (bx * (cx * cx + cy * cy) - cx * (bx * bx + by * by))
+ (ax * ax + ay * ay) * (bx * cy - by * cx);
det <= 0.0
}
pub fn flip_pass(&mut self) -> usize {
let n = self.triangles.len();
let mut edge_map: std::collections::HashMap<(usize, usize), Vec<usize>> =
std::collections::HashMap::new();
for (ti, tri) in self.triangles.iter().enumerate() {
for k in 0..3 {
let a = tri[k];
let b = tri[(k + 1) % 3];
let key = if a < b { (a, b) } else { (b, a) };
edge_map.entry(key).or_default().push(ti);
}
}
let mut flips = 0usize;
let candidates: Vec<((usize, usize), usize, usize)> = edge_map
.iter()
.filter_map(|(&key, tris)| {
if tris.len() == 2 {
Some((key, tris[0], tris[1]))
} else {
None
}
})
.collect();
for (edge_key, t0, t1) in candidates {
if t0 >= n || t1 >= n {
continue;
}
let tri0 = self.triangles[t0];
let tri1 = self.triangles[t1];
let (ea, eb) = edge_key;
let opp0 = tri0.iter().copied().find(|&v| v != ea && v != eb);
let opp1 = tri1.iter().copied().find(|&v| v != ea && v != eb);
let (c, d) = match (opp0, opp1) {
(Some(c), Some(d)) => (c, d),
_ => continue,
};
let va = self.vertices[ea];
let vb = self.vertices[eb];
let vc = self.vertices[c];
let vd = self.vertices[d];
if !Self::is_locally_delaunay(va, vb, vc, vd) {
self.triangles[t0] = [ea, c, d];
self.triangles[t1] = [eb, d, c];
flips += 1;
}
}
self.n_flips += flips;
flips
}
pub fn flip_to_delaunay(&mut self, max_passes: usize) {
for _ in 0..max_passes {
if self.flip_pass() == 0 {
break;
}
}
}
}
pub struct MeshStats {
pub n_vertices: usize,
pub n_triangles: usize,
pub n_edges: usize,
pub n_boundary_edges: usize,
pub n_non_manifold_edges: usize,
pub euler_characteristic: i64,
}
pub struct MeshRepair {
pub vertices: Vec<[f64; 3]>,
pub triangles: Vec<[usize; 3]>,
}
impl MeshRepair {
pub fn new(vertices: Vec<[f64; 3]>, triangles: Vec<[usize; 3]>) -> Self {
Self {
vertices,
triangles,
}
}
pub fn fill_holes(&mut self) -> usize {
let loops = find_boundary_loops(&self.triangles);
let n_holes = loops.len();
for lp in &loops {
if lp.len() < 3 {
continue;
}
let hub = lp[0];
for i in 1..(lp.len() - 1) {
self.triangles.push([hub, lp[i], lp[i + 1]]);
}
}
n_holes
}
pub fn fill_holes_ear(&mut self) -> usize {
let loops = find_boundary_loops(&self.triangles);
let n_holes = loops.len();
for lp in &loops {
let new_tris = fill_hole_ear_clipping(&self.vertices, lp);
self.triangles.extend_from_slice(&new_tris);
}
n_holes
}
pub fn remove_duplicate_vertices(&mut self, epsilon: f64) -> usize {
let (new_v, new_t, n_merged) =
merge_duplicate_vertices(&self.vertices, &self.triangles, epsilon);
self.vertices = new_v;
self.triangles = new_t;
n_merged
}
pub fn fix_non_manifold_edges(&mut self) -> usize {
let before = self.triangles.len();
self.triangles = fix_non_manifold_edges(&self.triangles);
before - self.triangles.len()
}
pub fn compute_euler_characteristic(&self) -> i32 {
let v = self.vertices.len();
let mut edge_set: HashSet<(usize, usize)> = HashSet::new();
for tri in &self.triangles {
for k in 0..3 {
let a = tri[k];
let b = tri[(k + 1) % 3];
let key = if a < b { (a, b) } else { (b, a) };
edge_set.insert(key);
}
}
let e = edge_set.len();
let f = self.triangles.len();
v as i32 - e as i32 + f as i32
}
}