oxihuman_morph/
pore_size_morph.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone, Copy, PartialEq)]
9pub enum PoreZone {
10 TZone,
11 Cheeks,
12 Forehead,
13 Chin,
14 Nose,
15}
16
17#[derive(Debug, Clone)]
19pub struct PoreSizeMorph {
20 pub global_size: f32,
21 pub zone_overrides: Vec<(PoreZone, f32)>,
22 pub depth: f32,
23 pub morph_count: usize,
24 pub enabled: bool,
25}
26
27impl PoreSizeMorph {
28 pub fn new(morph_count: usize) -> Self {
29 PoreSizeMorph {
30 global_size: 0.3,
31 zone_overrides: Vec::new(),
32 depth: 0.5,
33 morph_count,
34 enabled: true,
35 }
36 }
37}
38
39pub fn new_pore_size_morph(morph_count: usize) -> PoreSizeMorph {
41 PoreSizeMorph::new(morph_count)
42}
43
44pub fn psm_set_size(morph: &mut PoreSizeMorph, size: f32) {
46 morph.global_size = size.clamp(0.0, 1.0);
47}
48
49pub fn psm_set_zone(morph: &mut PoreSizeMorph, zone: PoreZone, size: f32) {
51 let v = size.clamp(0.0, 1.0);
52 if let Some(e) = morph.zone_overrides.iter_mut().find(|(z, _)| *z == zone) {
53 e.1 = v;
54 } else {
55 morph.zone_overrides.push((zone, v));
56 }
57}
58
59pub fn psm_set_depth(morph: &mut PoreSizeMorph, depth: f32) {
61 morph.depth = depth.clamp(0.0, 1.0);
62}
63
64pub fn psm_evaluate(morph: &PoreSizeMorph) -> Vec<f32> {
66 if !morph.enabled || morph.morph_count == 0 {
68 return vec![];
69 }
70 let w = morph.global_size * morph.depth;
71 vec![w; morph.morph_count]
72}
73
74pub fn psm_set_enabled(morph: &mut PoreSizeMorph, enabled: bool) {
76 morph.enabled = enabled;
77}
78
79pub fn psm_zone_count(morph: &PoreSizeMorph) -> usize {
81 morph.zone_overrides.len()
82}
83
84pub fn psm_to_json(morph: &PoreSizeMorph) -> String {
86 format!(
87 r#"{{"global_size":{},"depth":{},"zones":{},"morph_count":{},"enabled":{}}}"#,
88 morph.global_size,
89 morph.depth,
90 morph.zone_overrides.len(),
91 morph.morph_count,
92 morph.enabled
93 )
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99
100 #[test]
101 fn test_default_size() {
102 let m = new_pore_size_morph(4);
103 assert!((m.global_size - 0.3).abs() < 1e-6 );
104 }
105
106 #[test]
107 fn test_set_size_clamps() {
108 let mut m = new_pore_size_morph(4);
109 psm_set_size(&mut m, 2.0);
110 assert!((m.global_size - 1.0).abs() < 1e-6 );
111 }
112
113 #[test]
114 fn test_zone_added() {
115 let mut m = new_pore_size_morph(4);
116 psm_set_zone(&mut m, PoreZone::TZone, 0.7);
117 assert_eq!(psm_zone_count(&m), 1 );
118 }
119
120 #[test]
121 fn test_depth_clamped() {
122 let mut m = new_pore_size_morph(4);
123 psm_set_depth(&mut m, -1.0);
124 assert!((m.depth).abs() < 1e-6 );
125 }
126
127 #[test]
128 fn test_evaluate_length() {
129 let m = new_pore_size_morph(5);
130 assert_eq!(
131 psm_evaluate(&m).len(),
132 5 );
134 }
135
136 #[test]
137 fn test_evaluate_disabled() {
138 let mut m = new_pore_size_morph(4);
139 psm_set_enabled(&mut m, false);
140 assert!(psm_evaluate(&m).is_empty() );
141 }
142
143 #[test]
144 fn test_evaluate_product() {
145 let mut m = new_pore_size_morph(2);
146 psm_set_size(&mut m, 0.5);
147 psm_set_depth(&mut m, 0.4);
148 let out = psm_evaluate(&m);
149 assert!((out[0] - 0.2).abs() < 1e-5 );
150 }
151
152 #[test]
153 fn test_to_json_has_size() {
154 let m = new_pore_size_morph(4);
155 let j = psm_to_json(&m);
156 assert!(j.contains("\"global_size\"") );
157 }
158
159 #[test]
160 fn test_enabled_default() {
161 let m = new_pore_size_morph(4);
162 assert!(m.enabled );
163 }
164
165 #[test]
166 fn test_zone_update_not_duplicate() {
167 let mut m = new_pore_size_morph(4);
168 psm_set_zone(&mut m, PoreZone::Nose, 0.3);
169 psm_set_zone(&mut m, PoreZone::Nose, 0.7);
170 assert_eq!(
171 psm_zone_count(&m),
172 1 );
174 }
175}