oxihuman_export/
deform_bind_export.rs1#![allow(dead_code)]
4
5#[allow(dead_code)]
8#[derive(Debug, Clone)]
9pub struct DeformBindEntry {
10 pub deformer_name: String,
11 pub vertex_indices: Vec<u32>,
12 pub weights: Vec<f32>,
13}
14
15#[allow(dead_code)]
16#[derive(Debug, Clone)]
17pub struct DeformBindExport {
18 pub bindings: Vec<DeformBindEntry>,
19}
20
21#[allow(dead_code)]
22pub fn new_deform_bind_export() -> DeformBindExport {
23 DeformBindExport {
24 bindings: Vec::new(),
25 }
26}
27
28#[allow(dead_code)]
29pub fn add_binding(exp: &mut DeformBindExport, name: &str, indices: Vec<u32>, weights: Vec<f32>) {
30 exp.bindings.push(DeformBindEntry {
31 deformer_name: name.to_string(),
32 vertex_indices: indices,
33 weights,
34 });
35}
36
37#[allow(dead_code)]
38pub fn binding_count(exp: &DeformBindExport) -> usize {
39 exp.bindings.len()
40}
41
42#[allow(dead_code)]
43pub fn find_binding<'a>(exp: &'a DeformBindExport, name: &str) -> Option<&'a DeformBindEntry> {
44 exp.bindings.iter().find(|b| b.deformer_name == name)
45}
46
47#[allow(dead_code)]
48pub fn total_bound_vertices(exp: &DeformBindExport) -> usize {
49 exp.bindings.iter().map(|b| b.vertex_indices.len()).sum()
50}
51
52#[allow(dead_code)]
53pub fn binding_avg_weight(entry: &DeformBindEntry) -> f32 {
54 if entry.weights.is_empty() {
55 return 0.0;
56 }
57 entry.weights.iter().sum::<f32>() / entry.weights.len() as f32
58}
59
60#[allow(dead_code)]
61pub fn binding_is_valid(entry: &DeformBindEntry) -> bool {
62 entry.vertex_indices.len() == entry.weights.len()
63 && entry.weights.iter().all(|&w| (0.0..=1.0).contains(&w))
64}
65
66#[allow(dead_code)]
67pub fn deform_bind_to_json(exp: &DeformBindExport) -> String {
68 format!(
69 "{{\"binding_count\":{},\"total_vertices\":{}}}",
70 binding_count(exp),
71 total_bound_vertices(exp)
72 )
73}
74
75#[allow(dead_code)]
76pub fn normalize_binding_weights(entry: &mut DeformBindEntry) {
77 let sum: f32 = entry.weights.iter().sum();
78 if sum > 0.0 {
79 for w in &mut entry.weights {
80 *w /= sum;
81 }
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88
89 #[test]
90 fn test_empty() {
91 let exp = new_deform_bind_export();
92 assert_eq!(binding_count(&exp), 0);
93 }
94
95 #[test]
96 fn test_add_binding() {
97 let mut exp = new_deform_bind_export();
98 add_binding(&mut exp, "lattice", vec![0, 1, 2], vec![1.0, 0.8, 0.6]);
99 assert_eq!(binding_count(&exp), 1);
100 }
101
102 #[test]
103 fn test_find_binding() {
104 let mut exp = new_deform_bind_export();
105 add_binding(&mut exp, "curve", vec![5], vec![1.0]);
106 assert!(find_binding(&exp, "curve").is_some());
107 }
108
109 #[test]
110 fn test_total_bound_vertices() {
111 let mut exp = new_deform_bind_export();
112 add_binding(&mut exp, "a", vec![0, 1], vec![1.0, 1.0]);
113 add_binding(&mut exp, "b", vec![2, 3, 4], vec![0.5, 0.5, 0.5]);
114 assert_eq!(total_bound_vertices(&exp), 5);
115 }
116
117 #[test]
118 fn test_avg_weight() {
119 let entry = DeformBindEntry {
120 deformer_name: "x".to_string(),
121 vertex_indices: vec![0, 1],
122 weights: vec![1.0, 0.0],
123 };
124 assert!((binding_avg_weight(&entry) - 0.5).abs() < 1e-5);
125 }
126
127 #[test]
128 fn test_binding_is_valid() {
129 let entry = DeformBindEntry {
130 deformer_name: "x".to_string(),
131 vertex_indices: vec![0, 1],
132 weights: vec![0.5, 0.5],
133 };
134 assert!(binding_is_valid(&entry));
135 }
136
137 #[test]
138 fn test_binding_invalid_mismatch() {
139 let entry = DeformBindEntry {
140 deformer_name: "x".to_string(),
141 vertex_indices: vec![0, 1],
142 weights: vec![0.5],
143 };
144 assert!(!binding_is_valid(&entry));
145 }
146
147 #[test]
148 fn test_normalize() {
149 let mut entry = DeformBindEntry {
150 deformer_name: "x".to_string(),
151 vertex_indices: vec![0, 1],
152 weights: vec![2.0, 2.0],
153 };
154 normalize_binding_weights(&mut entry);
155 assert!((entry.weights.iter().sum::<f32>() - 1.0).abs() < 1e-5);
156 }
157
158 #[test]
159 fn test_json_output() {
160 let exp = new_deform_bind_export();
161 let j = deform_bind_to_json(&exp);
162 assert!(j.contains("binding_count"));
163 }
164
165 #[test]
166 fn test_find_missing() {
167 let exp = new_deform_bind_export();
168 assert!(find_binding(&exp, "missing").is_none());
169 }
170}