#![allow(dead_code)]
#[allow(dead_code)]
#[derive(Debug, Clone, Default)]
pub struct TensionMap {
pub values: Vec<f32>,
}
#[allow(dead_code)]
#[derive(Debug, Clone, Default)]
pub struct SkinTension {
pub map: TensionMap,
}
#[allow(dead_code)]
pub fn new_tension_map(n_verts: usize) -> TensionMap {
TensionMap { values: vec![0.0; n_verts] }
}
#[allow(dead_code)]
pub fn compute_tension(rest: &[f32], deformed: &[f32]) -> TensionMap {
let n = rest.len().min(deformed.len());
let values = (0..n).map(|i| (deformed[i] - rest[i]).abs()).collect();
TensionMap { values }
}
#[allow(dead_code)]
pub fn tension_at_vertex(map: &TensionMap, index: usize) -> f32 {
map.values.get(index).copied().unwrap_or(0.0)
}
#[allow(dead_code)]
pub fn max_tension(map: &TensionMap) -> f32 {
map.values.iter().cloned().fold(0.0_f32, f32::max)
}
#[allow(dead_code)]
pub fn min_tension(map: &TensionMap) -> f32 {
if map.values.is_empty() {
return 0.0;
}
map.values.iter().cloned().fold(f32::INFINITY, f32::min)
}
#[allow(dead_code)]
pub fn average_tension(map: &TensionMap) -> f32 {
if map.values.is_empty() {
return 0.0;
}
map.values.iter().sum::<f32>() / map.values.len() as f32
}
#[allow(dead_code)]
pub fn smooth_tension(map: &TensionMap) -> TensionMap {
let n = map.values.len();
if n == 0 {
return TensionMap::default();
}
let mut out = vec![0.0_f32; n];
#[allow(clippy::needless_range_loop)]
for i in 0..n {
let lo = if i == 0 { 0 } else { i - 1 };
let hi = (i + 1).min(n - 1);
out[i] = (map.values[lo] + map.values[i] + map.values[hi]) / 3.0;
}
TensionMap { values: out }
}
#[allow(dead_code)]
pub fn tension_to_color(map: &TensionMap) -> Vec<[u8; 4]> {
let max_t = max_tension(map).max(f32::EPSILON);
map.values
.iter()
.map(|&t| {
let ratio = (t / max_t).clamp(0.0, 1.0);
let r = (ratio * 255.0) as u8;
let b = ((1.0 - ratio) * 255.0) as u8;
[r, 0, b, 255]
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_tension_map_zeros() {
let m = new_tension_map(5);
assert_eq!(m.values.len(), 5);
assert!(m.values.iter().all(|&v| v == 0.0));
}
#[test]
fn test_compute_tension_no_deform() {
let rest = vec![0.0, 1.0, 2.0];
let m = compute_tension(&rest, &rest);
assert!(m.values.iter().all(|&v| v == 0.0));
}
#[test]
fn test_compute_tension_deformed() {
let rest = vec![0.0, 0.0, 0.0];
let def = vec![1.0, 2.0, 3.0];
let m = compute_tension(&rest, &def);
assert!((m.values[2] - 3.0).abs() < 1e-6);
}
#[test]
fn test_tension_at_vertex() {
let m = TensionMap { values: vec![0.1, 0.5, 0.9] };
assert!((tension_at_vertex(&m, 1) - 0.5).abs() < 1e-6);
}
#[test]
fn test_max_tension() {
let m = TensionMap { values: vec![0.1, 0.9, 0.5] };
assert!((max_tension(&m) - 0.9).abs() < 1e-6);
}
#[test]
fn test_min_tension() {
let m = TensionMap { values: vec![0.1, 0.9, 0.5] };
assert!((min_tension(&m) - 0.1).abs() < 1e-6);
}
#[test]
fn test_average_tension() {
let m = TensionMap { values: vec![0.0, 1.0] };
assert!((average_tension(&m) - 0.5).abs() < 1e-6);
}
#[test]
fn test_smooth_tension_reduces_extremes() {
let m = TensionMap { values: vec![0.0, 1.0, 0.0] };
let s = smooth_tension(&m);
assert!(s.values[1] < 1.0);
}
#[test]
fn test_tension_to_color_count() {
let m = TensionMap { values: vec![0.0, 0.5, 1.0] };
let colors = tension_to_color(&m);
assert_eq!(colors.len(), 3);
assert!(colors.iter().all(|c| c[3] == 255));
}
}