oxihuman_morph/
scapula_morph.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone)]
9pub struct ScapulaMorph {
10 pub size: f32,
11 pub winging: f32,
12 pub spine_prominence: f32,
13 pub rotation: f32,
14}
15
16impl ScapulaMorph {
17 pub fn new() -> Self {
18 Self {
19 size: 0.5,
20 winging: 0.0,
21 spine_prominence: 0.5,
22 rotation: 0.0,
23 }
24 }
25}
26
27impl Default for ScapulaMorph {
28 fn default() -> Self {
29 Self::new()
30 }
31}
32
33pub fn new_scapula_morph() -> ScapulaMorph {
35 ScapulaMorph::new()
36}
37
38pub fn scap_set_size(m: &mut ScapulaMorph, v: f32) {
40 m.size = v.clamp(0.0, 1.0);
41}
42
43pub fn scap_set_winging(m: &mut ScapulaMorph, v: f32) {
45 m.winging = v.clamp(0.0, 1.0);
46}
47
48pub fn scap_set_spine_prominence(m: &mut ScapulaMorph, v: f32) {
50 m.spine_prominence = v.clamp(0.0, 1.0);
51}
52
53pub fn scap_set_rotation(m: &mut ScapulaMorph, v: f32) {
55 m.rotation = v.clamp(-1.0, 1.0);
56}
57
58pub fn scap_visibility(m: &ScapulaMorph) -> f32 {
60 (m.spine_prominence * 0.6 + m.winging * 0.4).clamp(0.0, 1.0)
61}
62
63pub fn scapula_morph_to_json(m: &ScapulaMorph) -> String {
65 format!(
66 r#"{{"size":{:.4},"winging":{:.4},"spine_prominence":{:.4},"rotation":{:.4}}}"#,
67 m.size, m.winging, m.spine_prominence, m.rotation
68 )
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 #[test]
76 fn test_defaults() {
77 let m = new_scapula_morph();
78 assert_eq!(m.winging, 0.0);
79 assert!((m.size - 0.5).abs() < 1e-6);
80 }
81
82 #[test]
83 fn test_size_clamp() {
84 let mut m = new_scapula_morph();
85 scap_set_size(&mut m, 5.0);
86 assert_eq!(m.size, 1.0);
87 }
88
89 #[test]
90 fn test_winging_set() {
91 let mut m = new_scapula_morph();
92 scap_set_winging(&mut m, 0.6);
93 assert!((m.winging - 0.6).abs() < 1e-6);
94 }
95
96 #[test]
97 fn test_spine_prominence_set() {
98 let mut m = new_scapula_morph();
99 scap_set_spine_prominence(&mut m, 0.9);
100 assert!((m.spine_prominence - 0.9).abs() < 1e-6);
101 }
102
103 #[test]
104 fn test_rotation_clamp() {
105 let mut m = new_scapula_morph();
106 scap_set_rotation(&mut m, 3.0);
107 assert_eq!(m.rotation, 1.0);
108 }
109
110 #[test]
111 fn test_visibility_range() {
112 let m = new_scapula_morph();
113 let v = scap_visibility(&m);
114 assert!((0.0..=1.0).contains(&v));
115 }
116
117 #[test]
118 fn test_visibility_increases_with_winging() {
119 let mut m = new_scapula_morph();
120 let v0 = scap_visibility(&m);
121 scap_set_winging(&mut m, 1.0);
122 let v1 = scap_visibility(&m);
123 assert!(v1 > v0);
124 }
125
126 #[test]
127 fn test_json_keys() {
128 let m = new_scapula_morph();
129 let s = scapula_morph_to_json(&m);
130 assert!(s.contains("spine_prominence"));
131 }
132
133 #[test]
134 fn test_clone() {
135 let m = new_scapula_morph();
136 let m2 = m.clone();
137 assert!((m2.size - m.size).abs() < 1e-6);
138 }
139}