oxihuman_morph/
stretch_mark_morph.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone, Copy, PartialEq)]
9pub enum StretchMarkRegion {
10 Abdomen,
11 Hips,
12 Thighs,
13 UpperArms,
14 Breasts,
15}
16
17#[derive(Debug, Clone)]
19pub struct StretchMarkEntry {
20 pub region: StretchMarkRegion,
21 pub density: f32,
22 pub age_factor: f32,
23}
24
25#[derive(Debug, Clone)]
27pub struct StretchMarkMorph {
28 pub entries: Vec<StretchMarkEntry>,
29 pub global_intensity: f32,
30 pub morph_count: usize,
31 pub enabled: bool,
32}
33
34impl StretchMarkMorph {
35 pub fn new(morph_count: usize) -> Self {
36 StretchMarkMorph {
37 entries: Vec::new(),
38 global_intensity: 0.5,
39 morph_count,
40 enabled: true,
41 }
42 }
43}
44
45pub fn new_stretch_mark_morph(morph_count: usize) -> StretchMarkMorph {
47 StretchMarkMorph::new(morph_count)
48}
49
50pub fn smm_add_entry(morph: &mut StretchMarkMorph, entry: StretchMarkEntry) {
52 morph.entries.push(entry);
53}
54
55pub fn smm_set_intensity(morph: &mut StretchMarkMorph, intensity: f32) {
57 morph.global_intensity = intensity.clamp(0.0, 1.0);
58}
59
60pub fn smm_clear(morph: &mut StretchMarkMorph) {
62 morph.entries.clear();
63}
64
65pub fn smm_evaluate(morph: &StretchMarkMorph) -> Vec<f32> {
67 if !morph.enabled || morph.morph_count == 0 {
69 return vec![];
70 }
71 vec![morph.global_intensity; morph.morph_count]
72}
73
74pub fn smm_set_enabled(morph: &mut StretchMarkMorph, enabled: bool) {
76 morph.enabled = enabled;
77}
78
79pub fn smm_entry_count(morph: &StretchMarkMorph) -> usize {
81 morph.entries.len()
82}
83
84pub fn smm_to_json(morph: &StretchMarkMorph) -> String {
86 format!(
87 r#"{{"entry_count":{},"global_intensity":{},"morph_count":{},"enabled":{}}}"#,
88 morph.entries.len(),
89 morph.global_intensity,
90 morph.morph_count,
91 morph.enabled
92 )
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 fn make_entry() -> StretchMarkEntry {
100 StretchMarkEntry {
101 region: StretchMarkRegion::Abdomen,
102 density: 0.5,
103 age_factor: 0.3,
104 }
105 }
106
107 #[test]
108 fn test_initial_empty() {
109 let m = new_stretch_mark_morph(4);
110 assert_eq!(smm_entry_count(&m), 0 );
111 }
112
113 #[test]
114 fn test_add_entry() {
115 let mut m = new_stretch_mark_morph(4);
116 smm_add_entry(&mut m, make_entry());
117 assert_eq!(smm_entry_count(&m), 1 );
118 }
119
120 #[test]
121 fn test_clear() {
122 let mut m = new_stretch_mark_morph(4);
123 smm_add_entry(&mut m, make_entry());
124 smm_clear(&mut m);
125 assert_eq!(smm_entry_count(&m), 0 );
126 }
127
128 #[test]
129 fn test_intensity_clamp() {
130 let mut m = new_stretch_mark_morph(4);
131 smm_set_intensity(&mut m, 2.0);
132 assert!((m.global_intensity - 1.0).abs() < 1e-6 );
133 }
134
135 #[test]
136 fn test_evaluate_length() {
137 let m = new_stretch_mark_morph(5);
138 assert_eq!(
139 smm_evaluate(&m).len(),
140 5 );
142 }
143
144 #[test]
145 fn test_evaluate_disabled() {
146 let mut m = new_stretch_mark_morph(4);
147 smm_set_enabled(&mut m, false);
148 assert!(smm_evaluate(&m).is_empty() );
149 }
150
151 #[test]
152 fn test_to_json_has_entry_count() {
153 let m = new_stretch_mark_morph(4);
154 let j = smm_to_json(&m);
155 assert!(j.contains("\"entry_count\"") );
156 }
157
158 #[test]
159 fn test_enabled_default() {
160 let m = new_stretch_mark_morph(4);
161 assert!(m.enabled );
162 }
163
164 #[test]
165 fn test_evaluate_matches_intensity() {
166 let mut m = new_stretch_mark_morph(3);
167 smm_set_intensity(&mut m, 0.6);
168 let out = smm_evaluate(&m);
169 assert!((out[0] - 0.6).abs() < 1e-5 );
170 }
171
172 #[test]
173 fn test_region_variant() {
174 let e = StretchMarkEntry {
175 region: StretchMarkRegion::Thighs,
176 density: 0.4,
177 age_factor: 0.2,
178 };
179 assert_eq!(
180 e.region,
181 StretchMarkRegion::Thighs );
183 }
184}