oxihuman_morph/
piercing_deform.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone, Copy, PartialEq)]
9pub enum PiercingLocation {
10 EarLobe,
11 Nostril,
12 Septum,
13 Eyebrow,
14 Lip,
15 Navel,
16 Other,
17}
18
19#[derive(Debug, Clone)]
21pub struct PiercingEntry {
22 pub id: u32,
23 pub location: PiercingLocation,
24 pub gauge: f32,
25 pub deform_radius: f32,
26}
27
28#[derive(Debug, Clone)]
30pub struct PiercingDeform {
31 pub piercings: Vec<PiercingEntry>,
32 pub morph_count: usize,
33 pub enabled: bool,
34}
35
36impl PiercingDeform {
37 pub fn new(morph_count: usize) -> Self {
38 PiercingDeform {
39 piercings: Vec::new(),
40 morph_count,
41 enabled: true,
42 }
43 }
44}
45
46pub fn new_piercing_deform(morph_count: usize) -> PiercingDeform {
48 PiercingDeform::new(morph_count)
49}
50
51pub fn pd_add_piercing(ctrl: &mut PiercingDeform, entry: PiercingEntry) {
53 ctrl.piercings.push(entry);
54}
55
56pub fn pd_remove_piercing(ctrl: &mut PiercingDeform, id: u32) {
58 ctrl.piercings.retain(|p| p.id != id);
59}
60
61pub fn pd_evaluate(ctrl: &PiercingDeform) -> Vec<f32> {
63 if !ctrl.enabled || ctrl.morph_count == 0 {
65 return vec![];
66 }
67 let w: f32 = ctrl
68 .piercings
69 .iter()
70 .map(|p| p.deform_radius)
71 .sum::<f32>()
72 .min(1.0);
73 vec![w; ctrl.morph_count]
74}
75
76pub fn pd_set_enabled(ctrl: &mut PiercingDeform, enabled: bool) {
78 ctrl.enabled = enabled;
79}
80
81pub fn pd_piercing_count(ctrl: &PiercingDeform) -> usize {
83 ctrl.piercings.len()
84}
85
86pub fn pd_to_json(ctrl: &PiercingDeform) -> String {
88 format!(
89 r#"{{"piercing_count":{},"morph_count":{},"enabled":{}}}"#,
90 ctrl.piercings.len(),
91 ctrl.morph_count,
92 ctrl.enabled
93 )
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99
100 fn make_piercing(id: u32) -> PiercingEntry {
101 PiercingEntry {
102 id,
103 location: PiercingLocation::EarLobe,
104 gauge: 1.0,
105 deform_radius: 0.1,
106 }
107 }
108
109 #[test]
110 fn test_initial_empty() {
111 let c = new_piercing_deform(4);
112 assert_eq!(pd_piercing_count(&c), 0 );
113 }
114
115 #[test]
116 fn test_add_piercing() {
117 let mut c = new_piercing_deform(4);
118 pd_add_piercing(&mut c, make_piercing(1));
119 assert_eq!(pd_piercing_count(&c), 1 );
120 }
121
122 #[test]
123 fn test_remove_piercing() {
124 let mut c = new_piercing_deform(4);
125 pd_add_piercing(&mut c, make_piercing(1));
126 pd_remove_piercing(&mut c, 1);
127 assert_eq!(pd_piercing_count(&c), 0 );
128 }
129
130 #[test]
131 fn test_evaluate_length() {
132 let c = new_piercing_deform(6);
133 assert_eq!(
134 pd_evaluate(&c).len(),
135 6 );
137 }
138
139 #[test]
140 fn test_evaluate_disabled() {
141 let mut c = new_piercing_deform(4);
142 pd_set_enabled(&mut c, false);
143 assert!(pd_evaluate(&c).is_empty() );
144 }
145
146 #[test]
147 fn test_evaluate_capped() {
148 let mut c = new_piercing_deform(2);
149 for i in 0..20 {
150 pd_add_piercing(
151 &mut c,
152 PiercingEntry {
153 id: i,
154 location: PiercingLocation::Other,
155 gauge: 1.0,
156 deform_radius: 0.2,
157 },
158 );
159 }
160 let out = pd_evaluate(&c);
161 assert!(out[0] <= 1.0 );
162 }
163
164 #[test]
165 fn test_to_json_has_count() {
166 let c = new_piercing_deform(4);
167 let j = pd_to_json(&c);
168 assert!(j.contains("\"piercing_count\"") );
169 }
170
171 #[test]
172 fn test_enabled_default() {
173 let c = new_piercing_deform(4);
174 assert!(c.enabled );
175 }
176
177 #[test]
178 fn test_remove_nonexistent_is_noop() {
179 let mut c = new_piercing_deform(4);
180 pd_remove_piercing(&mut c, 999);
181 assert_eq!(
182 pd_piercing_count(&c),
183 0 );
185 }
186}