#![allow(dead_code)]
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PostureType {
Standing,
Sitting,
Crouching,
Leaning,
Supine,
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct BodyPosture {
pub name: String,
pub posture_type: PostureType,
pub spine_curve: f32,
pub shoulder_roll: f32,
pub hip_tilt: f32,
pub head_tilt: f32,
}
#[allow(dead_code)]
pub fn new_body_posture(name: &str, posture_type: PostureType) -> BodyPosture {
BodyPosture {
name: name.to_string(),
posture_type,
spine_curve: 0.0,
shoulder_roll: 0.0,
hip_tilt: 0.0,
head_tilt: 0.0,
}
}
#[allow(dead_code)]
pub fn posture_to_params(p: &BodyPosture) -> [f32; 4] {
[p.spine_curve, p.shoulder_roll, p.hip_tilt, p.head_tilt]
}
#[allow(dead_code)]
pub fn apply_posture(p: &mut BodyPosture, params: &[f32; 4]) {
p.spine_curve = params[0].clamp(-1.0, 1.0);
p.shoulder_roll = params[1].clamp(-1.0, 1.0);
p.hip_tilt = params[2].clamp(-1.0, 1.0);
p.head_tilt = params[3].clamp(-1.0, 1.0);
}
#[allow(dead_code)]
pub fn posture_blend(a: &BodyPosture, b: &BodyPosture, t: f32) -> BodyPosture {
let t = t.clamp(0.0, 1.0);
let inv = 1.0 - t;
BodyPosture {
name: a.name.clone(),
posture_type: if t < 0.5 { a.posture_type } else { b.posture_type },
spine_curve: a.spine_curve * inv + b.spine_curve * t,
shoulder_roll: a.shoulder_roll * inv + b.shoulder_roll * t,
hip_tilt: a.hip_tilt * inv + b.hip_tilt * t,
head_tilt: a.head_tilt * inv + b.head_tilt * t,
}
}
#[allow(dead_code)]
pub fn posture_name(p: &BodyPosture) -> &str {
&p.name
}
#[allow(dead_code)]
pub fn posture_type(p: &BodyPosture) -> PostureType {
p.posture_type
}
#[allow(dead_code)]
pub fn default_standing_posture() -> BodyPosture {
new_body_posture("default_standing", PostureType::Standing)
}
#[allow(dead_code)]
pub fn posture_deviation(p: &BodyPosture) -> f32 {
let params = posture_to_params(p);
params.iter().map(|v| v * v).sum::<f32>().sqrt()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_body_posture() {
let p = new_body_posture("stand", PostureType::Standing);
assert_eq!(p.name, "stand");
assert_eq!(p.posture_type, PostureType::Standing);
}
#[test]
fn test_posture_to_params_default() {
let p = default_standing_posture();
let params = posture_to_params(&p);
assert!(params.iter().all(|v| v.abs() < f32::EPSILON));
}
#[test]
fn test_apply_posture() {
let mut p = default_standing_posture();
apply_posture(&mut p, &[0.5, -0.3, 0.1, 0.2]);
assert!((p.spine_curve - 0.5).abs() < f32::EPSILON);
}
#[test]
fn test_apply_posture_clamps() {
let mut p = default_standing_posture();
apply_posture(&mut p, &[2.0, -2.0, 0.0, 0.0]);
assert!((p.spine_curve - 1.0).abs() < f32::EPSILON);
assert!((p.shoulder_roll - (-1.0)).abs() < f32::EPSILON);
}
#[test]
fn test_posture_blend_zero() {
let a = new_body_posture("a", PostureType::Standing);
let mut b = new_body_posture("b", PostureType::Sitting);
b.spine_curve = 1.0;
let result = posture_blend(&a, &b, 0.0);
assert!((result.spine_curve - 0.0).abs() < f32::EPSILON);
}
#[test]
fn test_posture_blend_one() {
let a = new_body_posture("a", PostureType::Standing);
let mut b = new_body_posture("b", PostureType::Sitting);
b.spine_curve = 1.0;
let result = posture_blend(&a, &b, 1.0);
assert!((result.spine_curve - 1.0).abs() < f32::EPSILON);
}
#[test]
fn test_posture_name() {
let p = new_body_posture("relaxed", PostureType::Leaning);
assert_eq!(posture_name(&p), "relaxed");
}
#[test]
fn test_posture_type_fn() {
let p = new_body_posture("sit", PostureType::Sitting);
assert_eq!(posture_type(&p), PostureType::Sitting);
}
#[test]
fn test_default_standing_posture() {
let p = default_standing_posture();
assert_eq!(p.posture_type, PostureType::Standing);
}
#[test]
fn test_posture_deviation() {
let p = default_standing_posture();
assert!(posture_deviation(&p).abs() < f32::EPSILON);
let mut p2 = default_standing_posture();
p2.spine_curve = 1.0;
assert!(posture_deviation(&p2) > 0.0);
}
}