oxihuman_morph/
brow_furrowing_control.rs1#![allow(dead_code)]
4
5#[allow(dead_code)]
9#[derive(Debug, Clone)]
10pub struct BrowFurrowConfig {
11 pub max_furrow: f32,
12}
13
14#[allow(dead_code)]
16#[derive(Debug, Clone)]
17pub struct BrowFurrowState {
18 pub inner_furrow: f32,
19 pub outer_furrow: f32,
20 pub vertical_pull: f32,
21}
22
23#[allow(dead_code)]
24pub fn default_brow_furrow_config() -> BrowFurrowConfig {
25 BrowFurrowConfig { max_furrow: 1.0 }
26}
27
28#[allow(dead_code)]
29pub fn new_brow_furrow_state() -> BrowFurrowState {
30 BrowFurrowState {
31 inner_furrow: 0.0,
32 outer_furrow: 0.0,
33 vertical_pull: 0.0,
34 }
35}
36
37#[allow(dead_code)]
38pub fn bfw_set_inner(state: &mut BrowFurrowState, cfg: &BrowFurrowConfig, v: f32) {
39 state.inner_furrow = v.clamp(0.0, cfg.max_furrow);
40}
41
42#[allow(dead_code)]
43pub fn bfw_set_outer(state: &mut BrowFurrowState, cfg: &BrowFurrowConfig, v: f32) {
44 state.outer_furrow = v.clamp(0.0, cfg.max_furrow);
45}
46
47#[allow(dead_code)]
48pub fn bfw_set_vertical(state: &mut BrowFurrowState, v: f32) {
49 state.vertical_pull = v.clamp(-1.0, 1.0);
50}
51
52#[allow(dead_code)]
53pub fn bfw_reset(state: &mut BrowFurrowState) {
54 *state = new_brow_furrow_state();
55}
56
57#[allow(dead_code)]
58pub fn bfw_is_neutral(state: &BrowFurrowState) -> bool {
59 let vals = [state.inner_furrow, state.outer_furrow, state.vertical_pull];
60 vals.iter().all(|v| v.abs() < 1e-6)
61}
62
63#[allow(dead_code)]
64pub fn bfw_intensity(state: &BrowFurrowState) -> f32 {
65 (state.inner_furrow + state.outer_furrow) * 0.5
66}
67
68#[allow(dead_code)]
69pub fn bfw_blend(a: &BrowFurrowState, b: &BrowFurrowState, t: f32) -> BrowFurrowState {
70 let t = t.clamp(0.0, 1.0);
71 BrowFurrowState {
72 inner_furrow: a.inner_furrow + (b.inner_furrow - a.inner_furrow) * t,
73 outer_furrow: a.outer_furrow + (b.outer_furrow - a.outer_furrow) * t,
74 vertical_pull: a.vertical_pull + (b.vertical_pull - a.vertical_pull) * t,
75 }
76}
77
78#[allow(dead_code)]
79pub fn bfw_to_weights(state: &BrowFurrowState) -> Vec<(String, f32)> {
80 vec![
81 ("brow_furrow_inner".to_string(), state.inner_furrow),
82 ("brow_furrow_outer".to_string(), state.outer_furrow),
83 ("brow_vertical_pull".to_string(), state.vertical_pull),
84 ]
85}
86
87#[allow(dead_code)]
88pub fn bfw_to_json(state: &BrowFurrowState) -> String {
89 format!(
90 r#"{{"inner_furrow":{:.4},"outer_furrow":{:.4},"vertical_pull":{:.4}}}"#,
91 state.inner_furrow, state.outer_furrow, state.vertical_pull
92 )
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn default_config() {
101 let cfg = default_brow_furrow_config();
102 assert!((cfg.max_furrow - 1.0).abs() < 1e-6);
103 }
104
105 #[test]
106 fn new_state_neutral() {
107 let s = new_brow_furrow_state();
108 assert!(bfw_is_neutral(&s));
109 }
110
111 #[test]
112 fn set_inner_clamps() {
113 let cfg = default_brow_furrow_config();
114 let mut s = new_brow_furrow_state();
115 bfw_set_inner(&mut s, &cfg, 5.0);
116 assert!((s.inner_furrow - 1.0).abs() < 1e-6);
117 }
118
119 #[test]
120 fn set_outer() {
121 let cfg = default_brow_furrow_config();
122 let mut s = new_brow_furrow_state();
123 bfw_set_outer(&mut s, &cfg, 0.6);
124 assert!((s.outer_furrow - 0.6).abs() < 1e-6);
125 }
126
127 #[test]
128 fn set_vertical_clamps_negative() {
129 let mut s = new_brow_furrow_state();
130 bfw_set_vertical(&mut s, -3.0);
131 assert!((s.vertical_pull + 1.0).abs() < 1e-6);
132 }
133
134 #[test]
135 fn intensity_average() {
136 let cfg = default_brow_furrow_config();
137 let mut s = new_brow_furrow_state();
138 bfw_set_inner(&mut s, &cfg, 0.4);
139 bfw_set_outer(&mut s, &cfg, 0.6);
140 assert!((bfw_intensity(&s) - 0.5).abs() < 1e-6);
141 }
142
143 #[test]
144 fn reset_clears() {
145 let cfg = default_brow_furrow_config();
146 let mut s = new_brow_furrow_state();
147 bfw_set_inner(&mut s, &cfg, 0.9);
148 bfw_reset(&mut s);
149 assert!(bfw_is_neutral(&s));
150 }
151
152 #[test]
153 fn blend_midpoint() {
154 let a = new_brow_furrow_state();
155 let cfg = default_brow_furrow_config();
156 let mut b = new_brow_furrow_state();
157 bfw_set_inner(&mut b, &cfg, 1.0);
158 let m = bfw_blend(&a, &b, 0.5);
159 assert!((m.inner_furrow - 0.5).abs() < 1e-6);
160 }
161
162 #[test]
163 fn to_weights_count() {
164 let s = new_brow_furrow_state();
165 assert_eq!(bfw_to_weights(&s).len(), 3);
166 }
167
168 #[test]
169 fn to_json_contains_fields() {
170 let s = new_brow_furrow_state();
171 let j = bfw_to_json(&s);
172 assert!(j.contains("inner_furrow"));
173 }
174}