#![allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct AuId(pub u8);
#[derive(Debug, Clone)]
pub struct ActionUnit {
pub id: AuId,
pub label: String,
pub weight: f32,
}
#[derive(Debug, Clone, Default)]
pub struct FacsFrame {
pub units: Vec<ActionUnit>,
}
impl ActionUnit {
pub fn new(id: u8, label: impl Into<String>) -> Self {
Self { id: AuId(id), label: label.into(), weight: 0.0 }
}
pub fn set_weight(&mut self, w: f32) {
self.weight = w.clamp(0.0, 1.0);
}
}
impl FacsFrame {
pub fn set(&mut self, id: u8, weight: f32) {
let w = weight.clamp(0.0, 1.0);
if let Some(au) = self.units.iter_mut().find(|a| a.id.0 == id) {
au.weight = w;
} else {
let mut au = ActionUnit::new(id, format!("AU{id:02}"));
au.weight = w;
self.units.push(au);
}
}
pub fn get(&self, id: u8) -> f32 {
self.units.iter().find(|a| a.id.0 == id).map(|a| a.weight).unwrap_or(0.0)
}
pub fn clear(&mut self) {
self.units.clear();
}
}
pub fn blend_facs_frames(a: &FacsFrame, b: &FacsFrame, t: f32) -> FacsFrame {
let t = t.clamp(0.0, 1.0);
let mut ids: Vec<u8> = a.units.iter().map(|u| u.id.0).collect();
for u in &b.units {
if !ids.contains(&u.id.0) {
ids.push(u.id.0);
}
}
let mut out = FacsFrame::default();
for id in ids {
let wa = a.get(id);
let wb = b.get(id);
out.set(id, wa + (wb - wa) * t);
}
out
}
pub fn active_units(frame: &FacsFrame, threshold: f32) -> Vec<u8> {
frame.units.iter().filter(|a| a.weight > threshold).map(|a| a.id.0).collect()
}
pub fn scale_frame(frame: &mut FacsFrame, factor: f32) {
for au in &mut frame.units {
au.weight = (au.weight * factor).clamp(0.0, 1.0);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_set_get() {
let mut f = FacsFrame::default();
f.set(1, 0.7);
assert!((f.get(1) - 0.7).abs() < 1e-6);
}
#[test]
fn test_missing_returns_zero() {
let f = FacsFrame::default();
assert_eq!(f.get(99), 0.0);
}
#[test]
fn test_clamp_weight() {
let mut f = FacsFrame::default();
f.set(4, 2.5);
assert!((f.get(4) - 1.0).abs() < 1e-6);
}
#[test]
fn test_clear() {
let mut f = FacsFrame::default();
f.set(1, 0.5);
f.clear();
assert!(f.units.is_empty());
}
#[test]
fn test_blend_frames() {
let mut a = FacsFrame::default();
a.set(1, 0.0);
let mut b = FacsFrame::default();
b.set(1, 1.0);
let blended = blend_facs_frames(&a, &b, 0.5);
assert!((blended.get(1) - 0.5).abs() < 1e-6);
}
#[test]
fn test_active_units() {
let mut f = FacsFrame::default();
f.set(1, 0.8);
f.set(2, 0.1);
let active = active_units(&f, 0.5);
assert!(active.contains(&1));
assert!(!active.contains(&2));
}
#[test]
fn test_scale_frame() {
let mut f = FacsFrame::default();
f.set(6, 0.5);
scale_frame(&mut f, 2.0);
assert!((f.get(6) - 1.0).abs() < 1e-6);
}
#[test]
fn test_action_unit_new() {
let au = ActionUnit::new(12, "AU12");
assert_eq!(au.weight, 0.0);
assert_eq!(au.id.0, 12);
}
#[test]
fn test_set_updates_existing() {
let mut f = FacsFrame::default();
f.set(7, 0.3);
f.set(7, 0.9);
assert_eq!(f.units.len(), 1);
assert!((f.get(7) - 0.9).abs() < 1e-6);
}
}