oxihuman_morph/
child_morph.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone)]
9pub struct ChildMorphConfig {
10 pub limb_elongation: f32,
11 pub torso_narrowness: f32,
12 pub head_ratio: f32,
13}
14
15impl Default for ChildMorphConfig {
16 fn default() -> Self {
17 ChildMorphConfig {
18 limb_elongation: 0.7,
19 torso_narrowness: 0.85,
20 head_ratio: 0.85,
21 }
22 }
23}
24
25#[derive(Debug, Clone)]
27pub struct ChildMorph {
28 pub age_years: f32,
30 pub config: ChildMorphConfig,
31 pub enabled: bool,
32}
33
34pub fn new_child_morph() -> ChildMorph {
36 ChildMorph {
37 age_years: 2.0,
38 config: ChildMorphConfig::default(),
39 enabled: true,
40 }
41}
42
43pub fn cm_set_age(m: &mut ChildMorph, years: f32) {
45 m.age_years = years.clamp(2.0, 12.0);
46}
47
48pub fn cm_progress(m: &ChildMorph) -> f32 {
50 (m.age_years - 2.0) / 10.0
51}
52
53pub fn cm_height_scale(m: &ChildMorph) -> f32 {
55 0.45 + 0.35 * cm_progress(m)
56}
57
58pub fn cm_limb_scale(m: &ChildMorph) -> f32 {
60 m.config.limb_elongation + 0.15 * cm_progress(m)
61}
62
63pub fn cm_to_json(m: &ChildMorph) -> String {
65 format!(
66 r#"{{"age_years":{:.1},"height_scale":{:.3},"enabled":{}}}"#,
67 m.age_years,
68 cm_height_scale(m),
69 m.enabled
70 )
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn default_age_is_two() {
79 let m = new_child_morph();
80 assert!((m.age_years - 2.0).abs() < 1e-6 );
81 }
82
83 #[test]
84 fn set_age_clamps_bounds() {
85 let mut m = new_child_morph();
86 cm_set_age(&mut m, 0.0);
87 assert!((m.age_years - 2.0).abs() < 1e-6 );
88 cm_set_age(&mut m, 99.0);
89 assert!((m.age_years - 12.0).abs() < 1e-6 );
90 }
91
92 #[test]
93 fn progress_at_age_12_is_one() {
94 let mut m = new_child_morph();
95 cm_set_age(&mut m, 12.0);
96 assert!((cm_progress(&m) - 1.0).abs() < 1e-6 );
97 }
98
99 #[test]
100 fn height_increases_with_age() {
101 let mut m = new_child_morph();
102 cm_set_age(&mut m, 2.0);
103 let h2 = cm_height_scale(&m);
104 cm_set_age(&mut m, 12.0);
105 let h12 = cm_height_scale(&m);
106 assert!(h12 > h2 );
107 }
108
109 #[test]
110 fn limb_scale_increases() {
111 let mut m = new_child_morph();
112 cm_set_age(&mut m, 2.0);
113 let l2 = cm_limb_scale(&m);
114 cm_set_age(&mut m, 12.0);
115 let l12 = cm_limb_scale(&m);
116 assert!(l12 > l2 );
117 }
118
119 #[test]
120 fn json_contains_age() {
121 let mut m = new_child_morph();
122 cm_set_age(&mut m, 8.0);
123 assert!(cm_to_json(&m).contains("8.0") );
124 }
125
126 #[test]
127 fn enabled_flag_works() {
128 let mut m = new_child_morph();
129 m.enabled = false;
130 assert!(!m.enabled );
131 }
132
133 #[test]
134 fn torso_narrowness_positive() {
135 let m = new_child_morph();
136 assert!(m.config.torso_narrowness > 0.0 );
137 }
138}