oxihuman_morph/
hair_part_morph.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone, Copy, PartialEq)]
9pub enum HairPartStyle {
10 Center,
11 Left,
12 Right,
13 NoParting,
14}
15
16#[derive(Debug, Clone)]
18pub struct HairPartMorph {
19 pub style: HairPartStyle,
20 pub offset: f32,
21 pub depth: f32,
22}
23
24impl HairPartMorph {
25 pub fn new() -> Self {
26 Self {
27 style: HairPartStyle::Center,
28 offset: 0.0,
29 depth: 0.5,
30 }
31 }
32}
33
34impl Default for HairPartMorph {
35 fn default() -> Self {
36 Self::new()
37 }
38}
39
40pub fn new_hair_part_morph() -> HairPartMorph {
42 HairPartMorph::new()
43}
44
45pub fn hair_part_set_offset(morph: &mut HairPartMorph, offset: f32) {
47 morph.offset = offset.clamp(-1.0, 1.0);
48}
49
50pub fn hair_part_set_depth(morph: &mut HairPartMorph, depth: f32) {
52 morph.depth = depth.clamp(0.0, 1.0);
53}
54
55pub fn hair_part_set_style(morph: &mut HairPartMorph, style: HairPartStyle) {
57 morph.style = style;
58}
59
60pub fn hair_part_infer_style(morph: &HairPartMorph) -> HairPartStyle {
62 if morph.offset < -0.1 {
63 HairPartStyle::Left
64 } else if morph.offset > 0.1 {
65 HairPartStyle::Right
66 } else {
67 HairPartStyle::Center
68 }
69}
70
71pub fn hair_part_morph_to_json(morph: &HairPartMorph) -> String {
73 let style_str = match morph.style {
74 HairPartStyle::Center => "center",
75 HairPartStyle::Left => "left",
76 HairPartStyle::Right => "right",
77 HairPartStyle::NoParting => "none",
78 };
79 format!(
80 r#"{{"style":"{style_str}","offset":{:.4},"depth":{:.4}}}"#,
81 morph.offset, morph.depth
82 )
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88
89 #[test]
90 fn test_defaults() {
91 let m = new_hair_part_morph();
92 assert_eq!(m.style, HairPartStyle::Center);
93 assert_eq!(m.offset, 0.0);
94 }
95
96 #[test]
97 fn test_offset_clamp_positive() {
98 let mut m = new_hair_part_morph();
99 hair_part_set_offset(&mut m, 2.0);
100 assert_eq!(m.offset, 1.0);
101 }
102
103 #[test]
104 fn test_offset_clamp_negative() {
105 let mut m = new_hair_part_morph();
106 hair_part_set_offset(&mut m, -2.0);
107 assert_eq!(m.offset, -1.0);
108 }
109
110 #[test]
111 fn test_depth_set() {
112 let mut m = new_hair_part_morph();
113 hair_part_set_depth(&mut m, 0.7);
114 assert!((m.depth - 0.7).abs() < 1e-6);
115 }
116
117 #[test]
118 fn test_style_set() {
119 let mut m = new_hair_part_morph();
120 hair_part_set_style(&mut m, HairPartStyle::Right);
121 assert_eq!(m.style, HairPartStyle::Right);
122 }
123
124 #[test]
125 fn test_infer_style_left() {
126 let mut m = new_hair_part_morph();
127 hair_part_set_offset(&mut m, -0.5);
128 assert_eq!(hair_part_infer_style(&m), HairPartStyle::Left);
129 }
130
131 #[test]
132 fn test_json_contains_style() {
133 let m = new_hair_part_morph();
134 let s = hair_part_morph_to_json(&m);
135 assert!(s.contains("style"));
136 }
137
138 #[test]
139 fn test_clone() {
140 let m = new_hair_part_morph();
141 let m2 = m.clone();
142 assert_eq!(m2.style, m.style);
143 }
144
145 #[test]
146 fn test_default_trait() {
147 let m: HairPartMorph = Default::default();
148 assert!((m.depth - 0.5).abs() < 1e-6);
149 }
150}