#![allow(dead_code)]
#[derive(Debug, Clone)]
pub struct RigSample {
pub pose_params: Vec<f32>,
pub shape_output: Vec<f32>,
}
#[derive(Debug, Clone)]
pub struct DataDrivenRig {
pub samples: Vec<RigSample>,
pub param_dim: usize,
pub shape_dim: usize,
pub enabled: bool,
}
impl DataDrivenRig {
pub fn new(param_dim: usize, shape_dim: usize) -> Self {
DataDrivenRig {
samples: Vec::new(),
param_dim,
shape_dim,
enabled: true,
}
}
}
pub fn new_data_driven_rig(param_dim: usize, shape_dim: usize) -> DataDrivenRig {
DataDrivenRig::new(param_dim, shape_dim)
}
pub fn ddr_add_sample(rig: &mut DataDrivenRig, sample: RigSample) {
rig.samples.push(sample);
}
fn euclidean_distance(a: &[f32], b: &[f32]) -> f32 {
let len = a.len().max(b.len());
let mut sum_sq = 0.0_f32;
for i in 0..len {
let ai = if i < a.len() { a[i] } else { 0.0 };
let bi = if i < b.len() { b[i] } else { 0.0 };
let diff = ai - bi;
sum_sq += diff * diff;
}
sum_sq.sqrt()
}
pub fn ddr_evaluate(rig: &DataDrivenRig, pose: &[f32]) -> Vec<f32> {
if rig.samples.is_empty() {
return vec![0.0; rig.shape_dim];
}
let mut weight_sum = 0.0_f32;
let mut accum = vec![0.0_f32; rig.shape_dim];
for sample in &rig.samples {
let dist = euclidean_distance(pose, &sample.pose_params);
if dist < 1e-9 {
let mut out = sample.shape_output.clone();
out.truncate(rig.shape_dim);
out.resize(rig.shape_dim, 0.0);
return out;
}
let w = 1.0 / dist;
weight_sum += w;
let contribution_len = sample.shape_output.len().min(rig.shape_dim);
for (a, &s) in accum[..contribution_len]
.iter_mut()
.zip(&sample.shape_output[..contribution_len])
{
*a += w * s;
}
}
if weight_sum == 0.0 {
return vec![0.0; rig.shape_dim];
}
for v in accum.iter_mut() {
*v /= weight_sum;
}
accum
}
pub fn ddr_sample_count(rig: &DataDrivenRig) -> usize {
rig.samples.len()
}
pub fn ddr_set_enabled(rig: &mut DataDrivenRig, enabled: bool) {
rig.enabled = enabled;
}
pub fn ddr_clear_samples(rig: &mut DataDrivenRig) {
rig.samples.clear();
}
pub fn ddr_to_json(rig: &DataDrivenRig) -> String {
format!(
r#"{{"param_dim":{},"shape_dim":{},"samples":{},"enabled":{}}}"#,
rig.param_dim,
rig.shape_dim,
rig.samples.len(),
rig.enabled
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_dims() {
let rig = new_data_driven_rig(10, 20);
assert_eq!(rig.param_dim, 10 ,);
assert_eq!(rig.shape_dim, 20 ,);
}
#[test]
fn test_no_samples_initially() {
let rig = new_data_driven_rig(5, 5);
assert_eq!(
ddr_sample_count(&rig),
0,
);
}
#[test]
fn test_add_sample() {
let mut rig = new_data_driven_rig(3, 3);
ddr_add_sample(
&mut rig,
RigSample {
pose_params: vec![0.1, 0.2, 0.3],
shape_output: vec![0.0, 0.0, 0.0],
},
);
assert_eq!(ddr_sample_count(&rig), 1 ,);
}
#[test]
fn test_evaluate_length() {
let rig = new_data_driven_rig(4, 6);
let out = ddr_evaluate(&rig, &[0.0; 4]);
assert_eq!(out.len(), 6 ,);
}
#[test]
fn test_evaluate_zeroed() {
let rig = new_data_driven_rig(2, 4);
let out = ddr_evaluate(&rig, &[1.0, 0.5]);
assert!(out.iter().all(|&v| v.abs() < 1e-6), );
}
#[test]
fn test_set_enabled() {
let mut rig = new_data_driven_rig(2, 2);
ddr_set_enabled(&mut rig, false);
assert!(!rig.enabled ,);
}
#[test]
fn test_clear_samples() {
let mut rig = new_data_driven_rig(2, 2);
ddr_add_sample(
&mut rig,
RigSample {
pose_params: vec![0.0; 2],
shape_output: vec![0.0; 2],
},
);
ddr_clear_samples(&mut rig);
assert_eq!(ddr_sample_count(&rig), 0 ,);
}
#[test]
fn test_to_json() {
let rig = new_data_driven_rig(4, 8);
let j = ddr_to_json(&rig);
assert!(j.contains("\"param_dim\""), );
}
#[test]
fn test_enabled_by_default() {
let rig = new_data_driven_rig(1, 1);
assert!(rig.enabled ,);
}
#[test]
fn test_many_samples() {
let mut rig = new_data_driven_rig(2, 2);
for _ in 0..10 {
ddr_add_sample(
&mut rig,
RigSample {
pose_params: vec![0.0; 2],
shape_output: vec![0.0; 2],
},
);
}
assert_eq!(
ddr_sample_count(&rig),
10,
);
}
#[test]
fn ddr_exact_pose_match_returns_sample() {
let mut rig = new_data_driven_rig(2, 2);
ddr_add_sample(
&mut rig,
RigSample {
pose_params: vec![1.0, 2.0],
shape_output: vec![0.7, 0.3],
},
);
let out = ddr_evaluate(&rig, &[1.0, 2.0]);
assert!((out[0] - 0.7).abs() < 1e-5, "expected 0.7 got {}", out[0]);
assert!((out[1] - 0.3).abs() < 1e-5, "expected 0.3 got {}", out[1]);
}
#[test]
fn ddr_two_samples_midpoint() {
let mut rig = new_data_driven_rig(1, 1);
ddr_add_sample(
&mut rig,
RigSample {
pose_params: vec![0.0],
shape_output: vec![1.0],
},
);
ddr_add_sample(
&mut rig,
RigSample {
pose_params: vec![2.0],
shape_output: vec![3.0],
},
);
let out = ddr_evaluate(&rig, &[1.0]);
assert!(
(out[0] - 2.0).abs() < 1e-5,
"expected 2.0 at midpoint, got {}",
out[0]
);
}
}