oxihuman_morph/
knee_shape_morph.rs1#![allow(dead_code)]
4
5pub struct KneeShapeMorph {
6 pub prominence: f32,
7 pub width: f32,
8 pub valgus_angle_deg: f32,
9}
10
11pub fn new_knee_shape_morph() -> KneeShapeMorph {
12 KneeShapeMorph {
13 prominence: 0.3,
14 width: 0.4,
15 valgus_angle_deg: 0.0,
16 }
17}
18
19pub fn knee_set_prominence(m: &mut KneeShapeMorph, v: f32) {
20 m.prominence = v.clamp(0.0, 1.0);
21}
22
23pub fn knee_is_valgus(m: &KneeShapeMorph) -> bool {
24 m.valgus_angle_deg > 5.0
25}
26
27pub fn knee_overall_weight(m: &KneeShapeMorph) -> f32 {
28 (m.prominence + m.width) * 0.5
29}
30
31pub fn knee_blend(a: &KneeShapeMorph, b: &KneeShapeMorph, t: f32) -> KneeShapeMorph {
32 let t = t.clamp(0.0, 1.0);
33 KneeShapeMorph {
34 prominence: a.prominence + (b.prominence - a.prominence) * t,
35 width: a.width + (b.width - a.width) * t,
36 valgus_angle_deg: a.valgus_angle_deg + (b.valgus_angle_deg - a.valgus_angle_deg) * t,
37 }
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43
44 #[test]
45 fn test_new() {
46 let m = new_knee_shape_morph();
48 assert!(m.prominence > 0.0);
49 }
50
51 #[test]
52 fn test_set_prominence() {
53 let mut m = new_knee_shape_morph();
55 knee_set_prominence(&mut m, 0.9);
56 assert!((m.prominence - 0.9).abs() < 1e-5);
57 }
58
59 #[test]
60 fn test_not_valgus_by_default() {
61 let m = new_knee_shape_morph();
63 assert!(!knee_is_valgus(&m));
64 }
65
66 #[test]
67 fn test_is_valgus() {
68 let m = KneeShapeMorph {
70 prominence: 0.3,
71 width: 0.4,
72 valgus_angle_deg: 10.0,
73 };
74 assert!(knee_is_valgus(&m));
75 }
76
77 #[test]
78 fn test_blend() {
79 let a = KneeShapeMorph {
81 prominence: 0.0,
82 width: 0.0,
83 valgus_angle_deg: 0.0,
84 };
85 let b = KneeShapeMorph {
86 prominence: 1.0,
87 width: 1.0,
88 valgus_angle_deg: 10.0,
89 };
90 let c = knee_blend(&a, &b, 0.5);
91 assert!((c.prominence - 0.5).abs() < 1e-5);
92 assert!((c.valgus_angle_deg - 5.0).abs() < 1e-4);
93 }
94}