use std::collections::HashMap;
use crate::{FaceVaryingChannel, Mesh};
fn ek(a: u32, b: u32) -> (u32, u32) {
if a <= b { (a, b) } else { (b, a) }
}
fn uf_find(parent: &mut [usize], mut x: usize) -> usize {
while parent[x] != x {
parent[x] = parent[parent[x]];
x = parent[x];
}
x
}
fn uf_union(parent: &mut [usize], a: usize, b: usize) {
let ra = uf_find(parent, a);
let rb = uf_find(parent, b);
if ra != rb {
parent[ra] = rb;
}
}
fn face_offsets(mesh: &Mesh) -> Vec<usize> {
let mut off = vec![0usize; mesh.face_vertex_counts.len() + 1];
for f in 0..mesh.face_vertex_counts.len() {
off[f + 1] = off[f] + mesh.face_vertex_counts[f] as usize;
}
off
}
pub(crate) fn creases_for(mesh: &Mesh, seam: &[[u32; 2]]) -> Vec<f32> {
let seam_set: std::collections::HashSet<(u32, u32)> =
seam.iter().map(|&[a, b]| ek(a, b)).collect();
mesh.edge_vertices
.iter()
.map(|&[a, b]| {
if seam_set.contains(&ek(a, b)) {
10.0
} else {
0.0
}
})
.collect()
}
pub(crate) fn seamed_position_channel(
mesh: &Mesh,
seam: &[[u32; 2]],
positions: &[[f32; 3]],
) -> (FaceVaryingChannel, Vec<[f32; 3]>) {
let seam_set: std::collections::HashSet<(u32, u32)> =
seam.iter().map(|&[a, b]| ek(a, b)).collect();
let face_count = mesh.face_vertex_counts.len();
let off = face_offsets(mesh);
let mut edge_faces: HashMap<(u32, u32), Vec<usize>> = HashMap::new();
for f in 0..face_count {
let n = mesh.face_vertex_counts[f] as usize;
for k in 0..n {
let a = mesh.face_vertex_indices[off[f] + k];
let b = mesh.face_vertex_indices[off[f] + (k + 1) % n];
edge_faces.entry(ek(a, b)).or_default().push(f);
}
}
let mut parent: Vec<usize> = (0..face_count).collect();
for (key, faces) in &edge_faces {
if faces.len() == 2 && !seam_set.contains(key) {
uf_union(&mut parent, faces[0], faces[1]);
}
}
let mut map: HashMap<(u32, usize), u32> = HashMap::new();
let mut indices = vec![0u32; off[face_count]];
let mut values: Vec<[f32; 3]> = Vec::new();
for f in 0..face_count {
let island = uf_find(&mut parent, f);
let n = mesh.face_vertex_counts[f] as usize;
for k in 0..n {
let v = mesh.face_vertex_indices[off[f] + k];
let id = *map.entry((v, island)).or_insert_with(|| {
let id = values.len() as u32;
values.push(positions[v as usize]);
id
});
indices[off[f] + k] = id;
}
}
(
FaceVaryingChannel {
indices,
value_count: values.len() as u32,
},
values,
)
}