oxihuman_morph/
nail_morph.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone, Copy, PartialEq)]
9pub enum NailShape {
10 Square,
11 Oval,
12 Round,
13 Almond,
14 Stiletto,
15 Coffin,
16}
17
18#[derive(Debug, Clone)]
20pub struct NailMorph {
21 pub shape: NailShape,
22 pub length: f32,
23 pub thickness: f32,
24 pub curvature: f32,
25 pub morph_count: usize,
26 pub enabled: bool,
27}
28
29impl NailMorph {
30 pub fn new(morph_count: usize) -> Self {
31 NailMorph {
32 shape: NailShape::Square,
33 length: 0.5,
34 thickness: 0.5,
35 curvature: 0.3,
36 morph_count,
37 enabled: true,
38 }
39 }
40}
41
42pub fn new_nail_morph(morph_count: usize) -> NailMorph {
44 NailMorph::new(morph_count)
45}
46
47pub fn nm_set_shape(morph: &mut NailMorph, shape: NailShape) {
49 morph.shape = shape;
50}
51
52pub fn nm_set_length(morph: &mut NailMorph, length: f32) {
54 morph.length = length.clamp(0.0, 1.0);
55}
56
57pub fn nm_set_thickness(morph: &mut NailMorph, thickness: f32) {
59 morph.thickness = thickness.clamp(0.0, 1.0);
60}
61
62pub fn nm_set_curvature(morph: &mut NailMorph, curvature: f32) {
64 morph.curvature = curvature.clamp(0.0, 1.0);
65}
66
67pub fn nm_evaluate(morph: &NailMorph) -> Vec<f32> {
69 if !morph.enabled || morph.morph_count == 0 {
71 return vec![];
72 }
73 let w = (morph.length + morph.curvature * 0.5) / 1.5;
74 vec![w.clamp(0.0, 1.0); morph.morph_count]
75}
76
77pub fn nm_set_enabled(morph: &mut NailMorph, enabled: bool) {
79 morph.enabled = enabled;
80}
81
82pub fn nm_to_json(morph: &NailMorph) -> String {
84 let shape = match morph.shape {
85 NailShape::Square => "square",
86 NailShape::Oval => "oval",
87 NailShape::Round => "round",
88 NailShape::Almond => "almond",
89 NailShape::Stiletto => "stiletto",
90 NailShape::Coffin => "coffin",
91 };
92 format!(
93 r#"{{"shape":"{}","length":{},"thickness":{},"curvature":{},"enabled":{}}}"#,
94 shape, morph.length, morph.thickness, morph.curvature, morph.enabled
95 )
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102 #[test]
103 fn test_default_shape() {
104 let m = new_nail_morph(4);
105 assert_eq!(
106 m.shape,
107 NailShape::Square );
109 }
110
111 #[test]
112 fn test_set_shape() {
113 let mut m = new_nail_morph(4);
114 nm_set_shape(&mut m, NailShape::Almond);
115 assert_eq!(m.shape, NailShape::Almond );
116 }
117
118 #[test]
119 fn test_length_clamped() {
120 let mut m = new_nail_morph(4);
121 nm_set_length(&mut m, 2.0);
122 assert!((m.length - 1.0).abs() < 1e-6 );
123 }
124
125 #[test]
126 fn test_thickness_clamped() {
127 let mut m = new_nail_morph(4);
128 nm_set_thickness(&mut m, -1.0);
129 assert!((m.thickness).abs() < 1e-6 );
130 }
131
132 #[test]
133 fn test_curvature_clamped() {
134 let mut m = new_nail_morph(4);
135 nm_set_curvature(&mut m, 5.0);
136 assert!((m.curvature - 1.0).abs() < 1e-6 );
137 }
138
139 #[test]
140 fn test_evaluate_length() {
141 let m = new_nail_morph(6);
142 assert_eq!(
143 nm_evaluate(&m).len(),
144 6 );
146 }
147
148 #[test]
149 fn test_evaluate_disabled() {
150 let mut m = new_nail_morph(4);
151 nm_set_enabled(&mut m, false);
152 assert!(nm_evaluate(&m).is_empty() );
153 }
154
155 #[test]
156 fn test_to_json_has_shape() {
157 let m = new_nail_morph(4);
158 let j = nm_to_json(&m);
159 assert!(j.contains("\"shape\"") );
160 }
161
162 #[test]
163 fn test_enabled_default() {
164 let m = new_nail_morph(4);
165 assert!(m.enabled );
166 }
167
168 #[test]
169 fn test_evaluate_in_range() {
170 let m = new_nail_morph(2);
171 let out = nm_evaluate(&m);
172 assert!(out[0] >= 0.0 && out[0] <= 1.0 );
173 }
174}