#![allow(dead_code)]
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CollapseEdgeV2 {
pub v0: u32,
pub v1: u32,
pub cost: u32, }
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct CollapseResultV2 {
pub new_positions: Vec<[f32; 3]>,
pub new_indices: Vec<u32>,
pub collapsed_count: usize,
}
#[allow(dead_code)]
pub fn edge_length_v2(positions: &[[f32; 3]], v0: u32, v1: u32) -> f32 {
let a = positions[v0 as usize];
let b = positions[v1 as usize];
let dx = a[0] - b[0];
let dy = a[1] - b[1];
let dz = a[2] - b[2];
(dx * dx + dy * dy + dz * dz).sqrt()
}
#[allow(dead_code)]
pub fn edge_midpoint_v2(positions: &[[f32; 3]], v0: u32, v1: u32) -> [f32; 3] {
let a = positions[v0 as usize];
let b = positions[v1 as usize];
[
(a[0] + b[0]) * 0.5,
(a[1] + b[1]) * 0.5,
(a[2] + b[2]) * 0.5,
]
}
#[allow(dead_code)]
pub fn collapse_single_edge(
positions: &mut [[f32; 3]],
indices: &mut Vec<u32>,
v0: u32,
v1: u32,
) -> bool {
if v0 == v1 {
return false;
}
let mid = edge_midpoint_v2(positions, v0, v1);
positions[v0 as usize] = mid;
for idx in indices.iter_mut() {
if *idx == v1 {
*idx = v0;
}
}
let tri_count = indices.len() / 3;
let mut keep = Vec::with_capacity(tri_count * 3);
for t in 0..tri_count {
let a = indices[t * 3];
let b = indices[t * 3 + 1];
let c = indices[t * 3 + 2];
if a != b && b != c && c != a {
keep.push(a);
keep.push(b);
keep.push(c);
}
}
*indices = keep;
true
}
#[allow(dead_code)]
pub fn find_shortest_edge(positions: &[[f32; 3]], indices: &[u32]) -> Option<(u32, u32)> {
let tri_count = indices.len() / 3;
if tri_count == 0 {
return None;
}
let mut best = (indices[0], indices[1]);
let mut best_len = f32::MAX;
for t in 0..tri_count {
let edges = [
(indices[t * 3], indices[t * 3 + 1]),
(indices[t * 3 + 1], indices[t * 3 + 2]),
(indices[t * 3 + 2], indices[t * 3]),
];
for (a, b) in edges {
let l = edge_length_v2(positions, a, b);
if l < best_len {
best_len = l;
best = (a, b);
}
}
}
Some(best)
}
#[allow(dead_code)]
pub fn unique_edge_count(indices: &[u32]) -> usize {
let mut edges = std::collections::HashSet::new();
let tri_count = indices.len() / 3;
for t in 0..tri_count {
let a = indices[t * 3];
let b = indices[t * 3 + 1];
let c = indices[t * 3 + 2];
for (s, e) in [(a, b), (b, c), (c, a)] {
let key = if s < e { (s, e) } else { (e, s) };
edges.insert(key);
}
}
edges.len()
}
#[allow(dead_code)]
pub fn collapse_n_edges(positions: &[[f32; 3]], indices: &[u32], n: usize) -> CollapseResultV2 {
let mut pos = positions.to_vec();
let mut idx = indices.to_vec();
let mut collapsed = 0;
for _ in 0..n {
if let Some((v0, v1)) = find_shortest_edge(&pos, &idx) {
if collapse_single_edge(&mut pos, &mut idx, v0, v1) {
collapsed += 1;
}
} else {
break;
}
}
CollapseResultV2 {
new_positions: pos,
new_indices: idx,
collapsed_count: collapsed,
}
}
#[allow(dead_code)]
pub fn collapse_result_to_json_v2(result: &CollapseResultV2) -> String {
format!(
"{{\"collapsed\":{},\"vertices\":{},\"triangles\":{}}}",
result.collapsed_count,
result.new_positions.len(),
result.new_indices.len() / 3,
)
}
#[cfg(test)]
mod tests {
use super::*;
fn two_tri_mesh() -> (Vec<[f32; 3]>, Vec<u32>) {
let pos = vec![
[0.0, 0.0, 0.0],
[1.0, 0.0, 0.0],
[0.5, 1.0, 0.0],
[1.5, 1.0, 0.0],
];
let idx = vec![0, 1, 2, 1, 3, 2];
(pos, idx)
}
#[test]
fn test_edge_length() {
let pos = vec![[0.0, 0.0, 0.0], [3.0, 4.0, 0.0]];
let l = edge_length_v2(&pos, 0, 1);
assert!((l - 5.0).abs() < 1e-6);
}
#[test]
fn test_edge_midpoint() {
let pos = vec![[0.0, 0.0, 0.0], [2.0, 0.0, 0.0]];
let m = edge_midpoint_v2(&pos, 0, 1);
assert!((m[0] - 1.0).abs() < 1e-6);
}
#[test]
fn test_find_shortest_edge() {
let (pos, idx) = two_tri_mesh();
let edge = find_shortest_edge(&pos, &idx);
assert!(edge.is_some());
}
#[test]
fn test_find_shortest_empty() {
assert!(find_shortest_edge(&[], &[]).is_none());
}
#[test]
fn test_unique_edge_count() {
let (_, idx) = two_tri_mesh();
assert_eq!(unique_edge_count(&idx), 5);
}
#[test]
fn test_collapse_single() {
let (mut pos, mut idx) = two_tri_mesh();
let ok = collapse_single_edge(&mut pos, &mut idx, 0, 1);
assert!(ok);
}
#[test]
fn test_collapse_n_edges() {
let (pos, idx) = two_tri_mesh();
let result = collapse_n_edges(&pos, &idx, 1);
assert_eq!(result.collapsed_count, 1);
}
#[test]
fn test_collapse_result_to_json() {
let (pos, idx) = two_tri_mesh();
let result = collapse_n_edges(&pos, &idx, 0);
let json = collapse_result_to_json_v2(&result);
assert!(json.contains("\"collapsed\":0"));
}
#[test]
fn test_collapse_same_vertex() {
let (mut pos, mut idx) = two_tri_mesh();
assert!(!collapse_single_edge(&mut pos, &mut idx, 0, 0));
}
#[test]
fn test_collapse_edge_struct() {
let e = CollapseEdgeV2 {
v0: 0,
v1: 1,
cost: 100,
};
assert_eq!(e.v0, 0);
assert_eq!(e.cost, 100);
}
}