#![allow(dead_code)]
#[derive(Debug, Clone)]
pub struct PsdExample {
pub pose: Vec<f32>,
pub deltas: Vec<[f32; 3]>,
pub weight: f32,
}
#[derive(Debug, Clone)]
pub struct PoseSpaceDeform {
pub examples: Vec<PsdExample>,
pub current_deltas: Vec<[f32; 3]>,
}
impl PoseSpaceDeform {
pub fn new(vertex_count: usize) -> Self {
PoseSpaceDeform {
examples: Vec::new(),
current_deltas: vec![[0.0; 3]; vertex_count],
}
}
}
pub fn new_psd(vertex_count: usize) -> PoseSpaceDeform {
PoseSpaceDeform::new(vertex_count)
}
pub fn psd_add_example(psd: &mut PoseSpaceDeform, pose: Vec<f32>, deltas: Vec<[f32; 3]>) {
psd.examples.push(PsdExample {
pose,
deltas,
weight: 0.0,
});
}
pub fn psd_example_count(psd: &PoseSpaceDeform) -> usize {
psd.examples.len()
}
pub fn psd_evaluate<'a>(psd: &'a mut PoseSpaceDeform, current_pose: &[f32]) -> &'a [[f32; 3]] {
for ex in &mut psd.examples {
let n = ex.pose.len().min(current_pose.len());
let dist: f32 = (0..n)
.map(|i| (ex.pose[i] - current_pose[i]).powi(2))
.sum::<f32>()
.sqrt();
ex.weight = if dist < 1e-6 { 1.0 } else { 1.0 / (1.0 + dist) };
}
if let Some(best) = psd.examples.iter().max_by(|a, b| {
a.weight
.partial_cmp(&b.weight)
.unwrap_or(std::cmp::Ordering::Equal)
}) {
let deltas = best.deltas.clone();
let n = psd.current_deltas.len().min(deltas.len());
psd.current_deltas[..n].copy_from_slice(&deltas[..n]);
}
&psd.current_deltas
}
pub fn psd_reset(psd: &mut PoseSpaceDeform) {
for d in &mut psd.current_deltas {
*d = [0.0; 3];
}
}
pub fn psd_to_json(psd: &PoseSpaceDeform) -> String {
format!(
r#"{{"examples":{},"vertices":{}}}"#,
psd.examples.len(),
psd.current_deltas.len()
)
}
pub fn psd_vertex_count(psd: &PoseSpaceDeform) -> usize {
psd.current_deltas.len()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_psd_vertex_count() {
let p = new_psd(12);
assert_eq!(psd_vertex_count(&p), 12 ,);
}
#[test]
fn test_initial_no_examples() {
let p = new_psd(5);
assert_eq!(
psd_example_count(&p),
0,
);
}
#[test]
fn test_add_example_increases_count() {
let mut p = new_psd(5);
psd_add_example(&mut p, vec![0.0; 4], vec![[0.0; 3]; 5]);
assert_eq!(psd_example_count(&p), 1 ,);
}
#[test]
fn test_evaluate_exact_pose_sets_deltas() {
let mut p = new_psd(3);
psd_add_example(&mut p, vec![1.0, 0.0], vec![[0.5, 0.0, 0.0]; 3]);
psd_evaluate(&mut p, &[1.0, 0.0]);
assert!(p.current_deltas[0][0] > 0.0, );
}
#[test]
fn test_reset_zeroes_deltas() {
let mut p = new_psd(3);
psd_add_example(&mut p, vec![0.0; 2], vec![[1.0; 3]; 3]);
psd_evaluate(&mut p, &[0.0; 2]);
psd_reset(&mut p);
for d in &p.current_deltas {
assert!((d[0]).abs() < 1e-6 ,);
}
}
#[test]
fn test_to_json_contains_examples() {
let p = new_psd(4);
let j = psd_to_json(&p);
assert!(j.contains("examples") ,);
}
#[test]
fn test_to_json_contains_vertices() {
let p = new_psd(7);
let j = psd_to_json(&p);
assert!(j.contains("7") ,);
}
#[test]
fn test_initial_deltas_zero() {
let p = new_psd(6);
for d in &p.current_deltas {
assert!((d[0]).abs() < 1e-6 ,);
}
}
#[test]
fn test_multiple_examples() {
let mut p = new_psd(2);
psd_add_example(&mut p, vec![0.0], vec![[0.0; 3]; 2]);
psd_add_example(&mut p, vec![1.0], vec![[1.0; 3]; 2]);
assert_eq!(
psd_example_count(&p),
2,
);
}
#[test]
fn test_example_weights_initially_zero() {
let mut p = new_psd(2);
psd_add_example(&mut p, vec![0.0], vec![[0.0; 3]; 2]);
assert!((p.examples[0].weight).abs() < 1e-6, );
}
#[test]
fn test_evaluate_no_examples_keeps_zero() {
let mut p = new_psd(3);
psd_evaluate(&mut p, &[0.5]);
for d in &p.current_deltas {
assert!((d[0]).abs() < 1e-6 ,);
}
}
}