oxihuman_morph/
hourglass_proportion.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone)]
9pub struct HourglassConfig {
10 pub bust_fullness: f32,
11 pub waist_cinch: f32,
12 pub hip_fullness: f32,
13}
14
15impl Default for HourglassConfig {
16 fn default() -> Self {
17 HourglassConfig {
18 bust_fullness: 0.7,
19 waist_cinch: 0.8,
20 hip_fullness: 0.75,
21 }
22 }
23}
24
25#[derive(Debug, Clone)]
27pub struct HourglassProportion {
28 pub intensity: f32,
29 pub config: HourglassConfig,
30 pub enabled: bool,
31}
32
33pub fn new_hourglass_proportion() -> HourglassProportion {
35 HourglassProportion {
36 intensity: 0.0,
37 config: HourglassConfig::default(),
38 enabled: true,
39 }
40}
41
42pub fn hg_set_intensity(m: &mut HourglassProportion, v: f32) {
44 m.intensity = v.clamp(0.0, 1.0);
45}
46
47pub fn hg_bust(m: &HourglassProportion) -> f32 {
49 m.intensity * m.config.bust_fullness
50}
51
52pub fn hg_waist(m: &HourglassProportion) -> f32 {
54 m.intensity * m.config.waist_cinch
55}
56
57pub fn hg_hips(m: &HourglassProportion) -> f32 {
59 m.intensity * m.config.hip_fullness
60}
61
62pub fn hg_whr(m: &HourglassProportion) -> f32 {
64 let base = 0.7_f32;
65 base - 0.15 * m.intensity
66}
67
68pub fn hg_to_json(m: &HourglassProportion) -> String {
70 format!(
71 r#"{{"intensity":{:.3},"whr":{:.3},"enabled":{}}}"#,
72 m.intensity,
73 hg_whr(m),
74 m.enabled
75 )
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 #[test]
83 fn default_zero() {
84 let m = new_hourglass_proportion();
85 assert!((m.intensity - 0.0).abs() < 1e-6 );
86 }
87
88 #[test]
89 fn clamp_intensity() {
90 let mut m = new_hourglass_proportion();
91 hg_set_intensity(&mut m, -1.0);
92 assert!((m.intensity - 0.0).abs() < 1e-6 );
93 }
94
95 #[test]
96 fn bust_at_max() {
97 let mut m = new_hourglass_proportion();
98 hg_set_intensity(&mut m, 1.0);
99 assert!((hg_bust(&m) - m.config.bust_fullness).abs() < 1e-6 );
100 }
101
102 #[test]
103 fn waist_cinch_zero_at_zero() {
104 let m = new_hourglass_proportion();
105 assert!((hg_waist(&m) - 0.0).abs() < 1e-6 );
106 }
107
108 #[test]
109 fn whr_decreases_with_intensity() {
110 let mut m = new_hourglass_proportion();
111 hg_set_intensity(&mut m, 0.0);
112 let whr0 = hg_whr(&m);
113 hg_set_intensity(&mut m, 1.0);
114 let whr1 = hg_whr(&m);
115 assert!(whr1 < whr0 );
116 }
117
118 #[test]
119 fn hips_at_half_intensity() {
120 let mut m = new_hourglass_proportion();
121 hg_set_intensity(&mut m, 0.5);
122 let h = hg_hips(&m);
123 assert!(h > 0.0 && h < 1.0 );
124 }
125
126 #[test]
127 fn json_contains_whr() {
128 let m = new_hourglass_proportion();
129 assert!(hg_to_json(&m).contains("whr") );
130 }
131
132 #[test]
133 fn enabled_default() {
134 let m = new_hourglass_proportion();
135 assert!(m.enabled );
136 }
137}