oxihuman_morph/
cage_morph.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone, Copy)]
9pub struct CageVertex {
10 pub position: [f32; 3],
11 pub delta: [f32; 3],
12}
13
14#[derive(Debug, Clone)]
16pub struct CageMorph {
17 pub cage_vertices: Vec<CageVertex>,
18 pub weight: f32,
19}
20
21impl CageMorph {
22 pub fn new(vertex_count: usize) -> Self {
23 CageMorph {
24 cage_vertices: (0..vertex_count)
25 .map(|_| CageVertex {
26 position: [0.0; 3],
27 delta: [0.0; 3],
28 })
29 .collect(),
30 weight: 0.0,
31 }
32 }
33}
34
35pub fn new_cage_morph(vertex_count: usize) -> CageMorph {
37 CageMorph::new(vertex_count)
38}
39
40pub fn cage_set_vertex(morph: &mut CageMorph, index: usize, position: [f32; 3], delta: [f32; 3]) {
42 if index < morph.cage_vertices.len() {
43 morph.cage_vertices[index] = CageVertex { position, delta };
44 }
45}
46
47pub fn cage_set_weight(morph: &mut CageMorph, weight: f32) {
49 morph.weight = weight.clamp(0.0, 1.0);
50}
51
52pub fn cage_to_json(morph: &CageMorph) -> String {
54 format!(
55 r#"{{"cage_vertices":{},"weight":{:.4}}}"#,
56 morph.cage_vertices.len(),
57 morph.weight
58 )
59}
60
61pub fn cage_vertex_count(morph: &CageMorph) -> usize {
63 morph.cage_vertices.len()
64}
65
66pub fn cage_total_delta_magnitude(morph: &CageMorph) -> f32 {
68 morph
69 .cage_vertices
70 .iter()
71 .map(|v| {
72 (v.delta[0] * v.delta[0] + v.delta[1] * v.delta[1] + v.delta[2] * v.delta[2]).sqrt()
73 })
74 .sum()
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
82 fn test_new_cage_vertex_count() {
83 let c = new_cage_morph(12);
84 assert_eq!(cage_vertex_count(&c), 12 ,);
85 }
86
87 #[test]
88 fn test_initial_weight_zero() {
89 let c = new_cage_morph(5);
90 assert!((c.weight).abs() < 1e-6, );
91 }
92
93 #[test]
94 fn test_set_vertex_updates() {
95 let mut c = new_cage_morph(4);
96 cage_set_vertex(&mut c, 0, [1.0, 2.0, 3.0], [0.1, 0.2, 0.3]);
97 let v = c.cage_vertices[0];
98 assert!((v.position[0] - 1.0).abs() < 1e-5, );
99 }
100
101 #[test]
102 fn test_set_weight_clamps_to_one() {
103 let mut c = new_cage_morph(2);
104 cage_set_weight(&mut c, 5.0);
105 assert!((c.weight - 1.0).abs() < 1e-5 ,);
106 }
107
108 #[test]
109 fn test_set_weight_negative_clamps() {
110 let mut c = new_cage_morph(2);
111 cage_set_weight(&mut c, -2.0);
112 assert!((c.weight).abs() < 1e-6, );
113 }
114
115 #[test]
116 fn test_to_json_contains_weight() {
117 let c = new_cage_morph(3);
118 let j = cage_to_json(&c);
119 assert!(j.contains("weight") ,);
120 }
121
122 #[test]
123 fn test_total_delta_zero_initially() {
124 let c = new_cage_morph(6);
125 assert!((cage_total_delta_magnitude(&c)).abs() < 1e-6, );
126 }
127
128 #[test]
129 fn test_total_delta_after_set() {
130 let mut c = new_cage_morph(2);
131 cage_set_vertex(&mut c, 0, [0.0; 3], [1.0, 0.0, 0.0]);
132 assert!(cage_total_delta_magnitude(&c) > 0.0, );
133 }
134
135 #[test]
136 fn test_set_out_of_bounds_ignored() {
137 let mut c = new_cage_morph(2);
138 cage_set_vertex(&mut c, 999, [1.0, 0.0, 0.0], [1.0, 0.0, 0.0]);
139 assert_eq!(
140 cage_vertex_count(&c),
141 2, );
143 }
144
145 #[test]
146 fn test_json_vertex_count() {
147 let c = new_cage_morph(7);
148 let j = cage_to_json(&c);
149 assert!(j.contains("7") ,);
150 }
151}