#![allow(dead_code)]
#[derive(Debug, Clone)]
pub struct CorrectivePoseDriverConfig {
pub threshold_rad: f32,
pub max_weight: f32,
}
impl Default for CorrectivePoseDriverConfig {
fn default() -> Self {
CorrectivePoseDriverConfig {
threshold_rad: 0.3,
max_weight: 1.0,
}
}
}
#[derive(Debug, Clone)]
pub struct CorrectivePoseDriver {
pub joint_name: String,
pub target_shape: String,
pub config: CorrectivePoseDriverConfig,
pub current_weight: f32,
}
impl CorrectivePoseDriver {
pub fn new(joint_name: &str, target_shape: &str) -> Self {
CorrectivePoseDriver {
joint_name: joint_name.to_string(),
target_shape: target_shape.to_string(),
config: CorrectivePoseDriverConfig::default(),
current_weight: 0.0,
}
}
}
pub fn new_corrective_pose_driver(joint_name: &str, target_shape: &str) -> CorrectivePoseDriver {
CorrectivePoseDriver::new(joint_name, target_shape)
}
pub fn evaluate_pose_driver(driver: &mut CorrectivePoseDriver, joint_angle_rad: f32) -> f32 {
let t = driver.config.threshold_rad;
let w = if joint_angle_rad >= t {
(joint_angle_rad - t) / (std::f32::consts::PI - t)
} else {
0.0
};
driver.current_weight = w.clamp(0.0, driver.config.max_weight);
driver.current_weight
}
pub fn reset_pose_driver(driver: &mut CorrectivePoseDriver) {
driver.current_weight = 0.0;
}
pub fn pose_driver_to_json(driver: &CorrectivePoseDriver) -> String {
format!(
r#"{{"joint":"{}","shape":"{}","weight":{:.4}}}"#,
driver.joint_name, driver.target_shape, driver.current_weight
)
}
pub fn set_pose_driver_threshold(driver: &mut CorrectivePoseDriver, threshold_rad: f32) {
driver.config.threshold_rad = threshold_rad.clamp(0.0, std::f32::consts::PI);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_driver_zero_weight() {
let d = new_corrective_pose_driver("shoulder", "shoulder_corrective");
assert!((d.current_weight).abs() < 1e-6, );
}
#[test]
fn test_evaluate_below_threshold_is_zero() {
let mut d = new_corrective_pose_driver("elbow", "elbow_bulge");
let w = evaluate_pose_driver(&mut d, 0.1);
assert!((w).abs() < 1e-6, );
}
#[test]
fn test_evaluate_above_threshold_positive() {
let mut d = new_corrective_pose_driver("elbow", "elbow_bulge");
let w = evaluate_pose_driver(&mut d, 1.5);
assert!(w > 0.0, );
}
#[test]
fn test_evaluate_clamps_to_max_weight() {
let mut d = new_corrective_pose_driver("knee", "knee_corrective");
let w = evaluate_pose_driver(&mut d, std::f32::consts::PI);
assert!(w <= d.config.max_weight, );
}
#[test]
fn test_reset_clears_weight() {
let mut d = new_corrective_pose_driver("hip", "hip_corrective");
evaluate_pose_driver(&mut d, 2.0);
reset_pose_driver(&mut d);
assert!((d.current_weight).abs() < 1e-6, );
}
#[test]
fn test_set_threshold() {
let mut d = new_corrective_pose_driver("wrist", "wrist_corrective");
set_pose_driver_threshold(&mut d, 0.8);
assert!((d.config.threshold_rad - 0.8).abs() < 1e-6, );
}
#[test]
fn test_to_json_contains_joint_name() {
let d = new_corrective_pose_driver("ankle", "ankle_corrective");
let s = pose_driver_to_json(&d);
assert!(s.contains("ankle"), );
}
#[test]
fn test_threshold_clamps_to_pi() {
let mut d = new_corrective_pose_driver("test", "test_shape");
set_pose_driver_threshold(&mut d, 99.0);
assert!(d.config.threshold_rad <= std::f32::consts::PI, );
}
#[test]
fn test_joint_name_stored() {
let d = new_corrective_pose_driver("shoulder_l", "shoulder_bulge");
assert_eq!(d.joint_name, "shoulder_l" ,);
}
#[test]
fn test_shape_name_stored() {
let d = new_corrective_pose_driver("hip", "hip_crease");
assert_eq!(
d.target_shape,
"hip_crease",
);
}
}