Skip to main content

oxihuman_morph/
alar_base_morph.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5#[derive(Debug, Clone)]
6pub struct AlarBaseMorph {
7    pub width: f32,
8    pub flare: f32,
9    pub elevation: f32,
10}
11
12pub fn new_alar_base_morph() -> AlarBaseMorph {
13    AlarBaseMorph {
14        width: 0.0,
15        flare: 0.0,
16        elevation: 0.0,
17    }
18}
19
20pub fn alar_set_width(m: &mut AlarBaseMorph, v: f32) {
21    m.width = v.clamp(0.0, 1.0);
22}
23
24pub fn alar_set_flare(m: &mut AlarBaseMorph, v: f32) {
25    m.flare = v.clamp(0.0, 1.0);
26}
27
28pub fn alar_overall_weight(m: &AlarBaseMorph) -> f32 {
29    (m.width + m.flare + m.elevation) / 3.0
30}
31
32pub fn alar_blend(a: &AlarBaseMorph, b: &AlarBaseMorph, t: f32) -> AlarBaseMorph {
33    let t = t.clamp(0.0, 1.0);
34    AlarBaseMorph {
35        width: a.width + (b.width - a.width) * t,
36        flare: a.flare + (b.flare - a.flare) * t,
37        elevation: a.elevation + (b.elevation - a.elevation) * t,
38    }
39}
40
41pub fn alar_is_wide(m: &AlarBaseMorph) -> bool {
42    m.width > 0.5
43}
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48
49    #[test]
50    fn test_new_defaults() {
51        /* fields start at zero */
52        let m = new_alar_base_morph();
53        assert_eq!(m.width, 0.0);
54        assert_eq!(m.flare, 0.0);
55        assert_eq!(m.elevation, 0.0);
56    }
57
58    #[test]
59    fn test_set_width_clamp_high() {
60        /* clamp above 1 */
61        let mut m = new_alar_base_morph();
62        alar_set_width(&mut m, 5.0);
63        assert_eq!(m.width, 1.0);
64    }
65
66    #[test]
67    fn test_set_width_clamp_low() {
68        /* clamp below 0 */
69        let mut m = new_alar_base_morph();
70        alar_set_width(&mut m, -1.0);
71        assert_eq!(m.width, 0.0);
72    }
73
74    #[test]
75    fn test_set_flare() {
76        /* normal value stored */
77        let mut m = new_alar_base_morph();
78        alar_set_flare(&mut m, 0.4);
79        assert!((m.flare - 0.4).abs() < 1e-6);
80    }
81
82    #[test]
83    fn test_overall_weight() {
84        /* mean of three */
85        let m = AlarBaseMorph {
86            width: 0.6,
87            flare: 0.3,
88            elevation: 0.9,
89        };
90        assert!((alar_overall_weight(&m) - 0.6).abs() < 1e-5);
91    }
92
93    #[test]
94    fn test_is_wide_false() {
95        /* below threshold */
96        let m = new_alar_base_morph();
97        assert!(!alar_is_wide(&m));
98    }
99
100    #[test]
101    fn test_is_wide_true() {
102        /* above threshold */
103        let m = AlarBaseMorph {
104            width: 0.8,
105            flare: 0.0,
106            elevation: 0.0,
107        };
108        assert!(alar_is_wide(&m));
109    }
110
111    #[test]
112    fn test_blend_midpoint() {
113        /* midpoint blend */
114        let a = AlarBaseMorph {
115            width: 0.0,
116            flare: 0.0,
117            elevation: 0.0,
118        };
119        let b = AlarBaseMorph {
120            width: 1.0,
121            flare: 1.0,
122            elevation: 1.0,
123        };
124        let c = alar_blend(&a, &b, 0.5);
125        assert!((c.width - 0.5).abs() < 1e-6);
126    }
127
128    #[test]
129    fn test_blend_clamp_t() {
130        /* t>1 clamped to 1 */
131        let a = AlarBaseMorph {
132            width: 0.0,
133            flare: 0.0,
134            elevation: 0.0,
135        };
136        let b = AlarBaseMorph {
137            width: 1.0,
138            flare: 1.0,
139            elevation: 1.0,
140        };
141        let c = alar_blend(&a, &b, 2.0);
142        assert!((c.width - 1.0).abs() < 1e-6);
143    }
144
145    #[test]
146    fn test_clone() {
147        /* clone independent */
148        let m = AlarBaseMorph {
149            width: 0.3,
150            flare: 0.4,
151            elevation: 0.5,
152        };
153        let m2 = m.clone();
154        assert_eq!(m.width, m2.width);
155    }
156}