#![allow(dead_code)]
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct DeltaVert {
pub index: usize,
pub dx: f32,
pub dy: f32,
pub dz: f32,
}
#[allow(dead_code)]
#[derive(Debug, Clone, Default)]
pub struct DeltaMorph {
pub name: String,
pub deltas: Vec<DeltaVert>,
}
#[allow(dead_code)]
pub fn new_delta_morph(name: &str) -> DeltaMorph {
DeltaMorph { name: name.to_owned(), deltas: Vec::new() }
}
#[allow(dead_code)]
pub fn add_delta(morph: &mut DeltaMorph, index: usize, dx: f32, dy: f32, dz: f32) {
morph.deltas.push(DeltaVert { index, dx, dy, dz });
}
#[allow(dead_code)]
pub fn apply_delta_morph(morph: &DeltaMorph, positions: &mut [f32], weight: f32) {
for d in &morph.deltas {
let base = d.index * 3;
if base + 2 < positions.len() {
positions[base] += d.dx * weight;
positions[base + 1] += d.dy * weight;
positions[base + 2] += d.dz * weight;
}
}
}
#[allow(dead_code)]
pub fn delta_magnitude(morph: &DeltaMorph) -> f32 {
morph
.deltas
.iter()
.map(|d| (d.dx * d.dx + d.dy * d.dy + d.dz * d.dz).sqrt())
.fold(0.0_f32, f32::max)
}
#[allow(dead_code)]
pub fn scale_delta(morph: &DeltaMorph, scale: f32) -> DeltaMorph {
DeltaMorph {
name: morph.name.clone(),
deltas: morph
.deltas
.iter()
.map(|d| DeltaVert { index: d.index, dx: d.dx * scale, dy: d.dy * scale, dz: d.dz * scale })
.collect(),
}
}
#[allow(dead_code)]
pub fn blend_deltas(a: &DeltaMorph, b: &DeltaMorph, t: f32) -> DeltaMorph {
let n = a.deltas.len().min(b.deltas.len());
let deltas = (0..n)
.map(|i| {
let da = a.deltas[i];
let db = b.deltas[i];
DeltaVert {
index: da.index,
dx: da.dx + (db.dx - da.dx) * t,
dy: da.dy + (db.dy - da.dy) * t,
dz: da.dz + (db.dz - da.dz) * t,
}
})
.collect();
DeltaMorph { name: format!("blend_{}_{}", a.name, b.name), deltas }
}
#[allow(dead_code)]
pub fn delta_count(morph: &DeltaMorph) -> usize {
morph.deltas.len()
}
#[allow(dead_code)]
pub fn delta_at(morph: &DeltaMorph, index: usize) -> Option<DeltaVert> {
morph.deltas.get(index).copied()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_delta_morph_empty() {
let m = new_delta_morph("smile");
assert_eq!(delta_count(&m), 0);
assert_eq!(m.name, "smile");
}
#[test]
fn test_add_delta_and_count() {
let mut m = new_delta_morph("test");
add_delta(&mut m, 0, 1.0, 0.0, 0.0);
add_delta(&mut m, 1, 0.0, 1.0, 0.0);
assert_eq!(delta_count(&m), 2);
}
#[test]
fn test_delta_at_some() {
let mut m = new_delta_morph("t");
add_delta(&mut m, 3, 0.1, 0.2, 0.3);
let d = delta_at(&m, 0).expect("should succeed");
assert_eq!(d.index, 3);
assert!((d.dx - 0.1).abs() < 1e-6);
}
#[test]
fn test_delta_at_none() {
let m = new_delta_morph("t");
assert!(delta_at(&m, 0).is_none());
}
#[test]
fn test_apply_delta_morph() {
let mut m = new_delta_morph("x");
add_delta(&mut m, 0, 1.0, 0.0, 0.0);
let mut pos = vec![0.0_f32; 3];
apply_delta_morph(&m, &mut pos, 0.5);
assert!((pos[0] - 0.5).abs() < 1e-6);
}
#[test]
fn test_delta_magnitude_single() {
let mut m = new_delta_morph("x");
add_delta(&mut m, 0, 3.0, 4.0, 0.0);
assert!((delta_magnitude(&m) - 5.0).abs() < 1e-5);
}
#[test]
fn test_scale_delta() {
let mut m = new_delta_morph("x");
add_delta(&mut m, 0, 1.0, 2.0, 3.0);
let s = scale_delta(&m, 2.0);
let d = delta_at(&s, 0).expect("should succeed");
assert!((d.dx - 2.0).abs() < 1e-6);
assert!((d.dz - 6.0).abs() < 1e-6);
}
#[test]
fn test_blend_deltas_midpoint() {
let mut a = new_delta_morph("a");
add_delta(&mut a, 0, 0.0, 0.0, 0.0);
let mut b = new_delta_morph("b");
add_delta(&mut b, 0, 2.0, 0.0, 0.0);
let c = blend_deltas(&a, &b, 0.5);
let d = delta_at(&c, 0).expect("should succeed");
assert!((d.dx - 1.0).abs() < 1e-6);
}
#[test]
fn test_blend_deltas_name() {
let a = new_delta_morph("a");
let b = new_delta_morph("b");
let c = blend_deltas(&a, &b, 0.0);
assert!(c.name.contains("a"));
assert!(c.name.contains("b"));
}
}