oxihuman_morph/
pregnancy_morph.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum Trimester {
10 First,
11 Second,
12 Third,
13 PostPartum,
14}
15
16#[derive(Debug, Clone)]
18pub struct PregnancyMorphConfig {
19 pub max_belly_scale: f32,
20 pub breast_scale_factor: f32,
21 pub hip_expansion: f32,
22}
23
24impl Default for PregnancyMorphConfig {
25 fn default() -> Self {
26 PregnancyMorphConfig {
27 max_belly_scale: 1.0,
28 breast_scale_factor: 0.4,
29 hip_expansion: 0.15,
30 }
31 }
32}
33
34#[derive(Debug, Clone)]
36pub struct PregnancyMorph {
37 pub weeks: f32,
38 pub config: PregnancyMorphConfig,
39 pub enabled: bool,
40}
41
42pub fn new_pregnancy_morph() -> PregnancyMorph {
44 PregnancyMorph {
45 weeks: 0.0,
46 config: PregnancyMorphConfig::default(),
47 enabled: true,
48 }
49}
50
51pub fn pm_set_weeks(m: &mut PregnancyMorph, weeks: f32) {
53 m.weeks = weeks.clamp(0.0, 42.0);
54}
55
56pub fn pm_trimester(m: &PregnancyMorph) -> Trimester {
58 if m.weeks < 13.0 {
59 Trimester::First
60 } else if m.weeks < 27.0 {
61 Trimester::Second
62 } else if m.weeks <= 42.0 {
63 Trimester::Third
64 } else {
65 Trimester::PostPartum
66 }
67}
68
69pub fn pm_belly_weight(m: &PregnancyMorph) -> f32 {
71 let t = (m.weeks / 40.0).clamp(0.0, 1.0);
72 t * t * m.config.max_belly_scale
73}
74
75pub fn pm_breast_delta(m: &PregnancyMorph) -> f32 {
77 let t = (m.weeks / 40.0).clamp(0.0, 1.0);
78 t * m.config.breast_scale_factor
79}
80
81pub fn pm_to_json(m: &PregnancyMorph) -> String {
83 format!(
84 r#"{{"weeks":{:.1},"enabled":{},"belly_weight":{:.3}}}"#,
85 m.weeks,
86 m.enabled,
87 pm_belly_weight(m)
88 )
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94
95 #[test]
96 fn default_is_zero_weeks() {
97 let m = new_pregnancy_morph();
98 assert!((m.weeks - 0.0).abs() < 1e-6 );
99 }
100
101 #[test]
102 fn set_weeks_clamps() {
103 let mut m = new_pregnancy_morph();
104 pm_set_weeks(&mut m, 999.0);
105 assert!((m.weeks - 42.0).abs() < 1e-6 );
106 pm_set_weeks(&mut m, -5.0);
107 assert!((m.weeks - 0.0).abs() < 1e-6 );
108 }
109
110 #[test]
111 fn trimester_first() {
112 let mut m = new_pregnancy_morph();
113 pm_set_weeks(&mut m, 8.0);
114 assert_eq!(
115 pm_trimester(&m),
116 Trimester::First );
118 }
119
120 #[test]
121 fn trimester_second() {
122 let mut m = new_pregnancy_morph();
123 pm_set_weeks(&mut m, 20.0);
124 assert_eq!(
125 pm_trimester(&m),
126 Trimester::Second );
128 }
129
130 #[test]
131 fn trimester_third() {
132 let mut m = new_pregnancy_morph();
133 pm_set_weeks(&mut m, 35.0);
134 assert_eq!(
135 pm_trimester(&m),
136 Trimester::Third );
138 }
139
140 #[test]
141 fn belly_weight_increases_with_weeks() {
142 let mut m = new_pregnancy_morph();
143 pm_set_weeks(&mut m, 10.0);
144 let w10 = pm_belly_weight(&m);
145 pm_set_weeks(&mut m, 30.0);
146 let w30 = pm_belly_weight(&m);
147 assert!(w30 > w10 );
148 }
149
150 #[test]
151 fn breast_delta_increases_with_weeks() {
152 let mut m = new_pregnancy_morph();
153 pm_set_weeks(&mut m, 5.0);
154 let d5 = pm_breast_delta(&m);
155 pm_set_weeks(&mut m, 38.0);
156 let d38 = pm_breast_delta(&m);
157 assert!(d38 > d5 );
158 }
159
160 #[test]
161 fn to_json_contains_weeks() {
162 let mut m = new_pregnancy_morph();
163 pm_set_weeks(&mut m, 20.0);
164 let j = pm_to_json(&m);
165 assert!(j.contains("20.0") );
166 }
167
168 #[test]
169 fn enabled_flag() {
170 let mut m = new_pregnancy_morph();
171 m.enabled = false;
172 assert!(!m.enabled );
173 }
174}