#![allow(dead_code)]
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq)]
pub struct VertexRing {
pub center: u32,
pub neighbors: Vec<u32>,
}
#[allow(dead_code)]
pub fn vertex_one_ring(indices: &[[u32; 3]], vertex: u32) -> Vec<u32> {
use std::collections::BTreeSet;
let mut neighbors = BTreeSet::new();
for tri in indices {
for i in 0..3 {
if tri[i] == vertex {
neighbors.insert(tri[(i + 1) % 3]);
neighbors.insert(tri[(i + 2) % 3]);
}
}
}
neighbors.into_iter().collect()
}
#[allow(dead_code)]
pub fn ring_size(ring: &[u32]) -> usize {
ring.len()
}
#[allow(dead_code)]
pub fn ring_centroid(positions: &[[f32; 3]], ring: &[u32]) -> [f32; 3] {
if ring.is_empty() {
return [0.0; 3];
}
let mut sum = [0.0f32; 3];
for &v in ring {
let p = positions[v as usize];
sum[0] += p[0];
sum[1] += p[1];
sum[2] += p[2];
}
let n = ring.len() as f32;
[sum[0] / n, sum[1] / n, sum[2] / n]
}
#[allow(dead_code)]
pub fn ring_normal(positions: &[[f32; 3]], indices: &[[u32; 3]], vertex: u32) -> [f32; 3] {
let mut sum = [0.0f32; 3];
for tri in indices {
if tri.contains(&vertex) {
let a = positions[tri[0] as usize];
let b = positions[tri[1] as usize];
let c = positions[tri[2] as usize];
let ab = [b[0] - a[0], b[1] - a[1], b[2] - a[2]];
let ac = [c[0] - a[0], c[1] - a[1], c[2] - a[2]];
sum[0] += ab[1] * ac[2] - ab[2] * ac[1];
sum[1] += ab[2] * ac[0] - ab[0] * ac[2];
sum[2] += ab[0] * ac[1] - ab[1] * ac[0];
}
}
let len = (sum[0] * sum[0] + sum[1] * sum[1] + sum[2] * sum[2]).sqrt();
if len < 1e-12 {
return [0.0; 3];
}
[sum[0] / len, sum[1] / len, sum[2] / len]
}
#[allow(dead_code)]
pub fn ring_is_boundary(indices: &[[u32; 3]], vertex: u32) -> bool {
use std::collections::HashMap;
let mut edge_count: HashMap<(u32, u32), u32> = HashMap::new();
for tri in indices {
if tri.contains(&vertex) {
for i in 0..3 {
let a = tri[i];
let b = tri[(i + 1) % 3];
let key = if a < b { (a, b) } else { (b, a) };
*edge_count.entry(key).or_insert(0) += 1;
}
}
}
edge_count.values().any(|&c| c == 1)
}
#[allow(dead_code)]
pub fn ring_area(positions: &[[f32; 3]], indices: &[[u32; 3]], vertex: u32) -> f32 {
let mut total = 0.0f32;
for tri in indices {
if tri.contains(&vertex) {
let a = positions[tri[0] as usize];
let b = positions[tri[1] as usize];
let c = positions[tri[2] as usize];
let ab = [b[0] - a[0], b[1] - a[1], b[2] - a[2]];
let ac = [c[0] - a[0], c[1] - a[1], c[2] - a[2]];
let cross = [
ab[1] * ac[2] - ab[2] * ac[1],
ab[2] * ac[0] - ab[0] * ac[2],
ab[0] * ac[1] - ab[1] * ac[0],
];
total += 0.5 * (cross[0] * cross[0] + cross[1] * cross[1] + cross[2] * cross[2]).sqrt();
}
}
total
}
#[allow(dead_code)]
pub fn ring_edges(indices: &[[u32; 3]], vertex: u32) -> Vec<(u32, u32)> {
use std::collections::BTreeSet;
let mut edges = BTreeSet::new();
for tri in indices {
if tri.contains(&vertex) {
for i in 0..3 {
let a = tri[i];
let b = tri[(i + 1) % 3];
if a == vertex || b == vertex {
let key = if a < b { (a, b) } else { (b, a) };
edges.insert(key);
}
}
}
}
edges.into_iter().collect()
}
#[allow(dead_code)]
pub fn ring_to_vec(ring: &VertexRing) -> Vec<u32> {
ring.neighbors.clone()
}
#[cfg(test)]
mod tests {
use super::*;
fn quad_mesh() -> (Vec<[f32; 3]>, Vec<[u32; 3]>) {
let p = vec![
[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0],
];
let i = vec![[0, 1, 2], [0, 2, 3]];
(p, i)
}
#[test]
fn test_vertex_one_ring() {
let (_, i) = quad_mesh();
let ring = vertex_one_ring(&i, 0);
assert_eq!(ring.len(), 3);
}
#[test]
fn test_ring_size() {
assert_eq!(ring_size(&[1, 2, 3]), 3);
}
#[test]
fn test_ring_centroid() {
let p = vec![[0.0, 0.0, 0.0], [2.0, 0.0, 0.0], [1.0, 2.0, 0.0]];
let c = ring_centroid(&p, &[0, 1, 2]);
assert!((c[0] - 1.0).abs() < 1e-6);
}
#[test]
fn test_ring_centroid_empty() {
let c = ring_centroid(&[], &[]);
assert_eq!(c, [0.0, 0.0, 0.0]);
}
#[test]
fn test_ring_normal() {
let (p, i) = quad_mesh();
let n = ring_normal(&p, &i, 0);
assert!((n[2] - 1.0).abs() < 1e-4);
}
#[test]
fn test_ring_is_boundary() {
let (_, i) = quad_mesh();
assert!(ring_is_boundary(&i, 1));
}
#[test]
fn test_ring_area() {
let (p, i) = quad_mesh();
let a = ring_area(&p, &i, 0);
assert!(a > 0.0);
}
#[test]
fn test_ring_edges() {
let (_, i) = quad_mesh();
let edges = ring_edges(&i, 0);
assert!(!edges.is_empty());
}
#[test]
fn test_ring_to_vec() {
let ring = VertexRing { center: 0, neighbors: vec![1, 2, 3] };
let v = ring_to_vec(&ring);
assert_eq!(v, vec![1, 2, 3]);
}
#[test]
fn test_vertex_one_ring_isolated() {
let i: Vec<[u32; 3]> = vec![[1, 2, 3]];
let ring = vertex_one_ring(&i, 0);
assert!(ring.is_empty());
}
}