Skip to main content

oxihuman_morph/
neck_length_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, PartialEq)]
6pub struct NeckLengthMorph {
7    pub length: f32,
8    pub width: f32,
9    pub forward_tilt: f32,
10}
11
12pub fn new_neck_length_morph() -> NeckLengthMorph {
13    NeckLengthMorph {
14        length: 0.5,
15        width: 0.5,
16        forward_tilt: 0.0,
17    }
18}
19
20pub fn neck_set_length(m: &mut NeckLengthMorph, v: f32) {
21    m.length = v.clamp(0.0, 1.0);
22}
23
24pub fn neck_set_width(m: &mut NeckLengthMorph, v: f32) {
25    m.width = v.clamp(0.0, 1.0);
26}
27
28pub fn neck_is_long(m: &NeckLengthMorph) -> bool {
29    m.length > 0.6
30}
31
32pub fn neck_overall_weight(m: &NeckLengthMorph) -> f32 {
33    (m.length + m.width + m.forward_tilt) / 3.0
34}
35
36pub fn neck_blend(a: &NeckLengthMorph, b: &NeckLengthMorph, t: f32) -> NeckLengthMorph {
37    let t = t.clamp(0.0, 1.0);
38    NeckLengthMorph {
39        length: a.length + (b.length - a.length) * t,
40        width: a.width + (b.width - a.width) * t,
41        forward_tilt: a.forward_tilt + (b.forward_tilt - a.forward_tilt) * t,
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48
49    #[test]
50    fn test_new_defaults() {
51        /* length starts at 0.5 */
52        let m = new_neck_length_morph();
53        assert!((m.length - 0.5).abs() < 1e-6);
54    }
55
56    #[test]
57    fn test_set_length_clamps_high() {
58        /* clamp above 1 */
59        let mut m = new_neck_length_morph();
60        neck_set_length(&mut m, 2.0);
61        assert!((m.length - 1.0).abs() < 1e-6);
62    }
63
64    #[test]
65    fn test_set_length_clamps_low() {
66        /* clamp below 0 */
67        let mut m = new_neck_length_morph();
68        neck_set_length(&mut m, -1.0);
69        assert!((m.length - 0.0).abs() < 1e-6);
70    }
71
72    #[test]
73    fn test_set_width() {
74        /* set width */
75        let mut m = new_neck_length_morph();
76        neck_set_width(&mut m, 0.7);
77        assert!((m.width - 0.7).abs() < 1e-6);
78    }
79
80    #[test]
81    fn test_is_long_true() {
82        /* length 0.8 => long */
83        let mut m = new_neck_length_morph();
84        neck_set_length(&mut m, 0.8);
85        assert!(neck_is_long(&m));
86    }
87
88    #[test]
89    fn test_is_long_false() {
90        /* default 0.5 not long */
91        let m = new_neck_length_morph();
92        assert!(!neck_is_long(&m));
93    }
94
95    #[test]
96    fn test_blend_at_one() {
97        /* blend t=1 returns b */
98        let a = new_neck_length_morph();
99        let mut b = new_neck_length_morph();
100        neck_set_length(&mut b, 1.0);
101        let r = neck_blend(&a, &b, 1.0);
102        assert!((r.length - 1.0).abs() < 1e-6);
103    }
104}