oxihuman_morph/
rosacea_morph.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone, Copy, PartialEq)]
9pub enum RosaceaSubtype {
10 Erythematotelangiectatic,
11 Papulopustular,
12 Phymatous,
13 Ocular,
14}
15
16#[derive(Debug, Clone)]
18pub struct RosaceaMorph {
19 pub subtype: RosaceaSubtype,
20 pub redness: f32,
21 pub telangiectasia: f32,
22 pub morph_count: usize,
23 pub enabled: bool,
24}
25
26impl RosaceaMorph {
27 pub fn new(morph_count: usize) -> Self {
28 RosaceaMorph {
29 subtype: RosaceaSubtype::Erythematotelangiectatic,
30 redness: 0.3,
31 telangiectasia: 0.2,
32 morph_count,
33 enabled: true,
34 }
35 }
36}
37
38pub fn new_rosacea_morph(morph_count: usize) -> RosaceaMorph {
40 RosaceaMorph::new(morph_count)
41}
42
43pub fn rsm_set_subtype(morph: &mut RosaceaMorph, subtype: RosaceaSubtype) {
45 morph.subtype = subtype;
46}
47
48pub fn rsm_set_redness(morph: &mut RosaceaMorph, redness: f32) {
50 morph.redness = redness.clamp(0.0, 1.0);
51}
52
53pub fn rsm_set_telangiectasia(morph: &mut RosaceaMorph, density: f32) {
55 morph.telangiectasia = density.clamp(0.0, 1.0);
56}
57
58pub fn rsm_evaluate(morph: &RosaceaMorph) -> Vec<f32> {
60 if !morph.enabled || morph.morph_count == 0 {
62 return vec![];
63 }
64 vec![morph.redness; morph.morph_count]
65}
66
67pub fn rsm_set_enabled(morph: &mut RosaceaMorph, enabled: bool) {
69 morph.enabled = enabled;
70}
71
72pub fn rsm_to_json(morph: &RosaceaMorph) -> String {
74 let sub = match morph.subtype {
75 RosaceaSubtype::Erythematotelangiectatic => "erythematotelangiectatic",
76 RosaceaSubtype::Papulopustular => "papulopustular",
77 RosaceaSubtype::Phymatous => "phymatous",
78 RosaceaSubtype::Ocular => "ocular",
79 };
80 format!(
81 r#"{{"subtype":"{}","redness":{},"telangiectasia":{},"morph_count":{},"enabled":{}}}"#,
82 sub, morph.redness, morph.telangiectasia, morph.morph_count, morph.enabled
83 )
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn test_default_subtype() {
92 let m = new_rosacea_morph(4);
93 assert_eq!(
94 m.subtype,
95 RosaceaSubtype::Erythematotelangiectatic );
97 }
98
99 #[test]
100 fn test_set_subtype() {
101 let mut m = new_rosacea_morph(4);
102 rsm_set_subtype(&mut m, RosaceaSubtype::Phymatous);
103 assert_eq!(
104 m.subtype,
105 RosaceaSubtype::Phymatous );
107 }
108
109 #[test]
110 fn test_redness_clamp() {
111 let mut m = new_rosacea_morph(4);
112 rsm_set_redness(&mut m, 2.0);
113 assert!((m.redness - 1.0).abs() < 1e-6 );
114 }
115
116 #[test]
117 fn test_telangiectasia_clamp() {
118 let mut m = new_rosacea_morph(4);
119 rsm_set_telangiectasia(&mut m, -0.1);
120 assert!(m.telangiectasia.abs() < 1e-6 );
121 }
122
123 #[test]
124 fn test_evaluate_length() {
125 let m = new_rosacea_morph(5);
126 assert_eq!(
127 rsm_evaluate(&m).len(),
128 5 );
130 }
131
132 #[test]
133 fn test_evaluate_disabled() {
134 let mut m = new_rosacea_morph(4);
135 rsm_set_enabled(&mut m, false);
136 assert!(rsm_evaluate(&m).is_empty() );
137 }
138
139 #[test]
140 fn test_to_json_has_subtype() {
141 let m = new_rosacea_morph(4);
142 let j = rsm_to_json(&m);
143 assert!(j.contains("\"subtype\"") );
144 }
145
146 #[test]
147 fn test_enabled_default() {
148 let m = new_rosacea_morph(4);
149 assert!(m.enabled );
150 }
151
152 #[test]
153 fn test_evaluate_matches_redness() {
154 let mut m = new_rosacea_morph(3);
155 rsm_set_redness(&mut m, 0.6);
156 let out = rsm_evaluate(&m);
157 assert!((out[0] - 0.6).abs() < 1e-5 );
158 }
159}