oxihuman_export/
abc_pointcloud_export.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone)]
9pub struct AbcPointcloudConfig {
10 pub object_path: String,
11 pub fps: f32,
12 pub frame_start: i32,
13 pub frame_end: i32,
14}
15
16impl Default for AbcPointcloudConfig {
17 fn default() -> Self {
18 Self {
19 object_path: "/pointcloud".to_string(),
20 fps: 24.0,
21 frame_start: 0,
22 frame_end: 1,
23 }
24 }
25}
26
27#[derive(Debug, Clone)]
29pub struct AbcPointcloudExport {
30 pub config: AbcPointcloudConfig,
31 pub frames: Vec<AbcPointcloudFrame>,
32}
33
34#[derive(Debug, Clone)]
36pub struct AbcPointcloudFrame {
37 pub frame: i32,
38 pub positions: Vec<[f32; 3]>,
39 pub radii: Vec<f32>,
40}
41
42pub fn new_abc_pointcloud(config: AbcPointcloudConfig) -> AbcPointcloudExport {
44 AbcPointcloudExport {
45 config,
46 frames: Vec::new(),
47 }
48}
49
50pub fn add_abc_frame(
52 export: &mut AbcPointcloudExport,
53 frame: i32,
54 positions: Vec<[f32; 3]>,
55 radii: Vec<f32>,
56) {
57 export.frames.push(AbcPointcloudFrame {
58 frame,
59 positions,
60 radii,
61 });
62}
63
64pub fn frame_count(export: &AbcPointcloudExport) -> usize {
66 export.frames.len()
67}
68
69pub fn total_point_count(export: &AbcPointcloudExport) -> usize {
71 export.frames.iter().map(|f| f.positions.len()).sum()
72}
73
74pub fn estimate_abc_size_bytes(export: &AbcPointcloudExport) -> usize {
76 export.frames.iter().map(|f| f.positions.len() * 16).sum()
78}
79
80pub fn validate_abc_pointcloud(export: &AbcPointcloudExport) -> bool {
82 export.config.fps > 0.0 && !export.frames.is_empty()
83}
84
85pub fn abc_pointcloud_config_to_json(config: &AbcPointcloudConfig) -> String {
87 format!(
88 r#"{{"object_path":"{}","fps":{},"frame_start":{},"frame_end":{}}}"#,
89 config.object_path, config.fps, config.frame_start, config.frame_end
90 )
91}
92
93pub fn frame_point_count(export: &AbcPointcloudExport, frame_idx: usize) -> usize {
95 export
96 .frames
97 .get(frame_idx)
98 .map(|f| f.positions.len())
99 .unwrap_or(0)
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 fn sample_export() -> AbcPointcloudExport {
107 let cfg = AbcPointcloudConfig::default();
108 let mut exp = new_abc_pointcloud(cfg);
109 add_abc_frame(
110 &mut exp,
111 0,
112 vec![[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]],
113 vec![0.1, 0.1],
114 );
115 exp
116 }
117
118 #[test]
119 fn test_frame_count() {
120 let exp = sample_export();
121 assert_eq!(frame_count(&exp), 1);
122 }
123
124 #[test]
125 fn test_total_point_count() {
126 let exp = sample_export();
127 assert_eq!(total_point_count(&exp), 2);
128 }
129
130 #[test]
131 fn test_estimate_size() {
132 let exp = sample_export();
133 assert!(estimate_abc_size_bytes(&exp) > 0);
134 }
135
136 #[test]
137 fn test_validate_valid() {
138 let exp = sample_export();
139 assert!(validate_abc_pointcloud(&exp));
140 }
141
142 #[test]
143 fn test_validate_empty_frames() {
144 let cfg = AbcPointcloudConfig::default();
145 let exp = new_abc_pointcloud(cfg);
146 assert!(!validate_abc_pointcloud(&exp));
147 }
148
149 #[test]
150 fn test_config_to_json() {
151 let cfg = AbcPointcloudConfig::default();
152 let json = abc_pointcloud_config_to_json(&cfg);
153 assert!(json.contains("pointcloud"));
154 }
155
156 #[test]
157 fn test_frame_point_count() {
158 let exp = sample_export();
159 assert_eq!(frame_point_count(&exp, 0), 2);
160 assert_eq!(frame_point_count(&exp, 99), 0);
161 }
162
163 #[test]
164 fn test_default_fps() {
165 let cfg = AbcPointcloudConfig::default();
166 assert!((cfg.fps - 24.0).abs() < 1e-6);
167 }
168
169 #[test]
170 fn test_add_multiple_frames() {
171 let cfg = AbcPointcloudConfig::default();
172 let mut exp = new_abc_pointcloud(cfg);
173 add_abc_frame(&mut exp, 0, vec![[0.0, 0.0, 0.0]], vec![0.1]);
174 add_abc_frame(
175 &mut exp,
176 1,
177 vec![[1.0, 0.0, 0.0], [2.0, 0.0, 0.0]],
178 vec![0.1, 0.2],
179 );
180 assert_eq!(total_point_count(&exp), 3);
181 }
182}