oxihuman_export/
envelope_export.rs1#![allow(dead_code)]
4
5#[allow(dead_code)]
9#[derive(Debug, Clone)]
10pub struct EnvelopeExport {
11 pub bone_name: String,
12 pub head_radius: f32,
13 pub tail_radius: f32,
14 pub distance: f32,
15}
16
17#[allow(dead_code)]
19#[derive(Debug, Clone)]
20pub struct EnvelopeBundle {
21 pub envelopes: Vec<EnvelopeExport>,
22}
23
24#[allow(dead_code)]
26pub fn new_envelope_bundle() -> EnvelopeBundle {
27 EnvelopeBundle { envelopes: vec![] }
28}
29
30#[allow(dead_code)]
32pub fn add_envelope(b: &mut EnvelopeBundle, bone: &str, head_r: f32, tail_r: f32, dist: f32) {
33 b.envelopes.push(EnvelopeExport {
34 bone_name: bone.to_string(),
35 head_radius: head_r,
36 tail_radius: tail_r,
37 distance: dist,
38 });
39}
40
41#[allow(dead_code)]
43pub fn env_count(b: &EnvelopeBundle) -> usize {
44 b.envelopes.len()
45}
46
47#[allow(dead_code)]
49pub fn get_envelope<'a>(b: &'a EnvelopeBundle, name: &str) -> Option<&'a EnvelopeExport> {
50 b.envelopes.iter().find(|e| e.bone_name == name)
51}
52
53#[allow(dead_code)]
55pub fn avg_radius(e: &EnvelopeExport) -> f32 {
56 (e.head_radius + e.tail_radius) * 0.5
57}
58
59#[allow(dead_code)]
61pub fn envelope_volume(e: &EnvelopeExport) -> f32 {
62 let r = avg_radius(e);
63 std::f32::consts::PI * r * r * e.distance + (4.0 / 3.0) * std::f32::consts::PI * r * r * r
64}
65
66#[allow(dead_code)]
68pub fn env_validate(b: &EnvelopeBundle) -> bool {
69 b.envelopes
70 .iter()
71 .all(|e| e.head_radius >= 0.0 && e.tail_radius >= 0.0 && e.distance >= 0.0)
72}
73
74#[allow(dead_code)]
76pub fn envelope_bundle_to_json(b: &EnvelopeBundle) -> String {
77 format!("{{\"count\":{}}}", env_count(b))
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83 #[test]
84 fn test_new() {
85 let b = new_envelope_bundle();
86 assert_eq!(env_count(&b), 0);
87 }
88 #[test]
89 fn test_add() {
90 let mut b = new_envelope_bundle();
91 add_envelope(&mut b, "arm", 0.1, 0.05, 0.3);
92 assert_eq!(env_count(&b), 1);
93 }
94 #[test]
95 fn test_get() {
96 let mut b = new_envelope_bundle();
97 add_envelope(&mut b, "leg", 0.1, 0.1, 0.5);
98 assert!(get_envelope(&b, "leg").is_some());
99 }
100 #[test]
101 fn test_get_missing() {
102 let b = new_envelope_bundle();
103 assert!(get_envelope(&b, "x").is_none());
104 }
105 #[test]
106 fn test_avg_radius() {
107 let e = EnvelopeExport {
108 bone_name: "a".to_string(),
109 head_radius: 0.2,
110 tail_radius: 0.4,
111 distance: 1.0,
112 };
113 assert!((avg_radius(&e) - 0.3).abs() < 1e-6);
114 }
115 #[test]
116 fn test_volume() {
117 let e = EnvelopeExport {
118 bone_name: "a".to_string(),
119 head_radius: 1.0,
120 tail_radius: 1.0,
121 distance: 1.0,
122 };
123 assert!(envelope_volume(&e) > 0.0);
124 }
125 #[test]
126 fn test_validate() {
127 let mut b = new_envelope_bundle();
128 add_envelope(&mut b, "a", 0.1, 0.1, 0.5);
129 assert!(env_validate(&b));
130 }
131 #[test]
132 fn test_validate_bad() {
133 let mut b = new_envelope_bundle();
134 add_envelope(&mut b, "a", -0.1, 0.1, 0.5);
135 assert!(!env_validate(&b));
136 }
137 #[test]
138 fn test_to_json() {
139 let b = new_envelope_bundle();
140 assert!(envelope_bundle_to_json(&b).contains("\"count\":0"));
141 }
142 #[test]
143 fn test_zero_distance() {
144 let e = EnvelopeExport {
145 bone_name: "a".to_string(),
146 head_radius: 0.5,
147 tail_radius: 0.5,
148 distance: 0.0,
149 };
150 assert!(envelope_volume(&e) > 0.0);
151 }
152}