oxihuman_morph/
hip_tilt_morph.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone)]
9pub struct HipTiltMorphConfig {
10 pub lateral_tilt: f32,
11 pub anterior_tilt: f32,
12 pub pelvic_rotation: f32,
13}
14
15impl Default for HipTiltMorphConfig {
16 fn default() -> Self {
17 Self {
18 lateral_tilt: 0.0,
19 anterior_tilt: 0.0,
20 pelvic_rotation: 0.0,
21 }
22 }
23}
24
25#[derive(Debug, Clone)]
27pub struct HipTiltMorph {
28 pub config: HipTiltMorphConfig,
29 pub intensity: f32,
30 pub enabled: bool,
31}
32
33impl HipTiltMorph {
34 pub fn new() -> Self {
35 Self {
36 config: HipTiltMorphConfig::default(),
37 intensity: 0.0,
38 enabled: true,
39 }
40 }
41}
42
43impl Default for HipTiltMorph {
44 fn default() -> Self {
45 Self::new()
46 }
47}
48
49pub fn new_hip_tilt_morph() -> HipTiltMorph {
51 HipTiltMorph::new()
52}
53
54pub fn hip_tilt_set_lateral(morph: &mut HipTiltMorph, v: f32) {
56 morph.config.lateral_tilt = v.clamp(-1.0, 1.0);
57}
58
59pub fn hip_tilt_set_anterior(morph: &mut HipTiltMorph, v: f32) {
61 morph.config.anterior_tilt = v.clamp(-1.0, 1.0);
62}
63
64pub fn hip_tilt_set_rotation(morph: &mut HipTiltMorph, v: f32) {
66 morph.config.pelvic_rotation = v.clamp(-1.0, 1.0);
67}
68
69pub fn hip_tilt_magnitude(morph: &HipTiltMorph) -> f32 {
71 let l = morph.config.lateral_tilt;
72 let a = morph.config.anterior_tilt;
73 ((l * l + a * a).sqrt() * morph.intensity).min(1.0)
74}
75
76pub fn hip_tilt_to_json(morph: &HipTiltMorph) -> String {
78 format!(
79 r#"{{"intensity":{},"lateral_tilt":{},"anterior_tilt":{},"pelvic_rotation":{}}}"#,
80 morph.intensity,
81 morph.config.lateral_tilt,
82 morph.config.anterior_tilt,
83 morph.config.pelvic_rotation,
84 )
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 #[test]
92 fn test_new() {
93 let m = new_hip_tilt_morph();
94 assert!((m.config.lateral_tilt - 0.0).abs() < 1e-6 );
95 }
96
97 #[test]
98 fn test_lateral_clamp() {
99 let mut m = new_hip_tilt_morph();
100 hip_tilt_set_lateral(&mut m, 5.0);
101 assert!((m.config.lateral_tilt - 1.0).abs() < 1e-6 );
102 }
103
104 #[test]
105 fn test_anterior_negative() {
106 let mut m = new_hip_tilt_morph();
107 hip_tilt_set_anterior(&mut m, -0.4);
108 assert!((m.config.anterior_tilt - (-0.4)).abs() < 1e-6 );
109 }
110
111 #[test]
112 fn test_rotation() {
113 let mut m = new_hip_tilt_morph();
114 hip_tilt_set_rotation(&mut m, 0.5);
115 assert!((m.config.pelvic_rotation - 0.5).abs() < 1e-6 );
116 }
117
118 #[test]
119 fn test_magnitude_zero() {
120 let m = new_hip_tilt_morph();
121 assert!((hip_tilt_magnitude(&m) - 0.0).abs() < 1e-6 );
122 }
123
124 #[test]
125 fn test_magnitude_nonzero() {
126 let mut m = new_hip_tilt_morph();
127 hip_tilt_set_lateral(&mut m, 1.0);
128 m.intensity = 1.0;
129 assert!(hip_tilt_magnitude(&m) > 0.0 );
130 }
131
132 #[test]
133 fn test_json_key() {
134 let m = new_hip_tilt_morph();
135 let j = hip_tilt_to_json(&m);
136 assert!(j.contains("lateral_tilt") );
137 }
138
139 #[test]
140 fn test_default_enabled() {
141 let m = HipTiltMorph::default();
142 assert!(m.enabled );
143 }
144
145 #[test]
146 fn test_clone() {
147 let m = new_hip_tilt_morph();
148 let c = m.clone();
149 assert!((c.intensity - m.intensity).abs() < 1e-6 );
150 }
151}