oxihuman_morph/
lip_volume_morph.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone, Copy, PartialEq)]
9pub enum LipArea {
10 Upper,
11 Lower,
12 Both,
13 Cupid,
14 Corners,
15}
16
17#[derive(Debug, Clone)]
19pub struct LipVolumeMorph {
20 pub area: LipArea,
21 pub volume: f32,
22 pub projection: f32,
23 pub definition: f32,
24 pub morph_count: usize,
25 pub enabled: bool,
26}
27
28impl LipVolumeMorph {
29 pub fn new(morph_count: usize) -> Self {
30 LipVolumeMorph {
31 area: LipArea::Both,
32 volume: 0.5,
33 projection: 0.5,
34 definition: 0.5,
35 morph_count,
36 enabled: true,
37 }
38 }
39}
40
41pub fn new_lip_volume_morph(morph_count: usize) -> LipVolumeMorph {
43 LipVolumeMorph::new(morph_count)
44}
45
46pub fn lvm_set_area(morph: &mut LipVolumeMorph, area: LipArea) {
48 morph.area = area;
49}
50
51pub fn lvm_set_volume(morph: &mut LipVolumeMorph, volume: f32) {
53 morph.volume = volume.clamp(0.0, 1.0);
54}
55
56pub fn lvm_set_projection(morph: &mut LipVolumeMorph, projection: f32) {
58 morph.projection = projection.clamp(0.0, 1.0);
59}
60
61pub fn lvm_set_definition(morph: &mut LipVolumeMorph, definition: f32) {
63 morph.definition = definition.clamp(0.0, 1.0);
64}
65
66pub fn lvm_evaluate(morph: &LipVolumeMorph) -> Vec<f32> {
68 if !morph.enabled || morph.morph_count == 0 {
70 return vec![];
71 }
72 let w = (morph.volume + morph.projection) * 0.5;
73 vec![w.clamp(0.0, 1.0); morph.morph_count]
74}
75
76pub fn lvm_set_enabled(morph: &mut LipVolumeMorph, enabled: bool) {
78 morph.enabled = enabled;
79}
80
81pub fn lvm_to_json(morph: &LipVolumeMorph) -> String {
83 let area = match morph.area {
84 LipArea::Upper => "upper",
85 LipArea::Lower => "lower",
86 LipArea::Both => "both",
87 LipArea::Cupid => "cupid",
88 LipArea::Corners => "corners",
89 };
90 format!(
91 r#"{{"area":"{}","volume":{},"projection":{},"definition":{},"enabled":{}}}"#,
92 area, morph.volume, morph.projection, morph.definition, morph.enabled
93 )
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99
100 #[test]
101 fn test_default_area() {
102 let m = new_lip_volume_morph(4);
103 assert_eq!(m.area, LipArea::Both );
104 }
105
106 #[test]
107 fn test_set_area() {
108 let mut m = new_lip_volume_morph(4);
109 lvm_set_area(&mut m, LipArea::Upper);
110 assert_eq!(m.area, LipArea::Upper );
111 }
112
113 #[test]
114 fn test_volume_clamped() {
115 let mut m = new_lip_volume_morph(4);
116 lvm_set_volume(&mut m, 2.0);
117 assert!((m.volume - 1.0).abs() < 1e-6 );
118 }
119
120 #[test]
121 fn test_projection_clamped() {
122 let mut m = new_lip_volume_morph(4);
123 lvm_set_projection(&mut m, -1.0);
124 assert!((m.projection).abs() < 1e-6 );
125 }
126
127 #[test]
128 fn test_definition_clamped() {
129 let mut m = new_lip_volume_morph(4);
130 lvm_set_definition(&mut m, 1.5);
131 assert!((m.definition - 1.0).abs() < 1e-6 );
132 }
133
134 #[test]
135 fn test_evaluate_length() {
136 let m = new_lip_volume_morph(6);
137 assert_eq!(
138 lvm_evaluate(&m).len(),
139 6 );
141 }
142
143 #[test]
144 fn test_evaluate_disabled() {
145 let mut m = new_lip_volume_morph(4);
146 lvm_set_enabled(&mut m, false);
147 assert!(lvm_evaluate(&m).is_empty() );
148 }
149
150 #[test]
151 fn test_evaluate_avg() {
152 let mut m = new_lip_volume_morph(2);
153 lvm_set_volume(&mut m, 0.6);
154 lvm_set_projection(&mut m, 0.4);
155 let out = lvm_evaluate(&m);
156 assert!((out[0] - 0.5).abs() < 1e-5 );
157 }
158
159 #[test]
160 fn test_to_json_has_area() {
161 let m = new_lip_volume_morph(4);
162 let j = lvm_to_json(&m);
163 assert!(j.contains("\"area\"") );
164 }
165
166 #[test]
167 fn test_enabled_default() {
168 let m = new_lip_volume_morph(4);
169 assert!(m.enabled );
170 }
171}