oxihuman_export/
ptx_export.rs1#![allow(dead_code)]
4
5#[allow(dead_code)]
9pub struct PtxHeader {
10 pub cols: u32,
11 pub rows: u32,
12 pub scanner_pos: [f64; 3],
13 pub scanner_axes: [[f64; 3]; 3],
14}
15
16#[allow(dead_code)]
18pub struct PtxPoint {
19 pub x: f64,
20 pub y: f64,
21 pub z: f64,
22 pub intensity: f32,
23 pub r: u8,
24 pub g: u8,
25 pub b: u8,
26}
27
28#[allow(dead_code)]
30pub struct PtxExport {
31 pub header: PtxHeader,
32 pub points: Vec<PtxPoint>,
33}
34
35#[allow(dead_code)]
37pub fn new_ptx_export(cols: u32, rows: u32) -> PtxExport {
38 PtxExport {
39 header: PtxHeader {
40 cols,
41 rows,
42 scanner_pos: [0.0; 3],
43 scanner_axes: [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
44 },
45 points: Vec::new(),
46 }
47}
48
49#[allow(dead_code)]
51pub fn add_ptx_point(export: &mut PtxExport, x: f64, y: f64, z: f64, intensity: f32) {
52 export.points.push(PtxPoint {
53 x,
54 y,
55 z,
56 intensity,
57 r: 255,
58 g: 255,
59 b: 255,
60 });
61}
62
63#[allow(dead_code)]
65pub fn ptx_point_count(export: &PtxExport) -> usize {
66 export.points.len()
67}
68
69#[allow(dead_code)]
71pub fn build_ptx_header_string(export: &PtxExport) -> String {
72 format!(
73 "{}\n{}\n{:.6} {:.6} {:.6}\n",
74 export.header.cols,
75 export.header.rows,
76 export.header.scanner_pos[0],
77 export.header.scanner_pos[1],
78 export.header.scanner_pos[2],
79 )
80}
81
82#[allow(dead_code)]
84pub fn validate_ptx(export: &PtxExport) -> bool {
85 export.header.cols > 0 && export.header.rows > 0
86}
87
88#[allow(dead_code)]
90pub fn export_ptx_string(export: &PtxExport) -> String {
91 let mut s = build_ptx_header_string(export);
92 for p in &export.points {
93 s.push_str(&format!(
94 "{:.6} {:.6} {:.6} {:.3}\n",
95 p.x, p.y, p.z, p.intensity
96 ));
97 }
98 s
99}
100
101#[allow(dead_code)]
103pub fn ptx_from_positions(positions: &[[f32; 3]]) -> PtxExport {
104 let n = positions.len() as u32;
105 let mut e = new_ptx_export(n, 1);
106 for &p in positions {
107 add_ptx_point(&mut e, p[0] as f64, p[1] as f64, p[2] as f64, 1.0);
108 }
109 e
110}
111
112#[allow(dead_code)]
114pub fn ptx_file_size_estimate(point_count: usize) -> usize {
115 point_count * 50 + 100
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 #[test]
123 fn new_export() {
124 let e = new_ptx_export(100, 100);
125 assert_eq!(ptx_point_count(&e), 0);
126 }
127
128 #[test]
129 fn add_point() {
130 let mut e = new_ptx_export(100, 100);
131 add_ptx_point(&mut e, 1.0, 2.0, 3.0, 0.5);
132 assert_eq!(ptx_point_count(&e), 1);
133 }
134
135 #[test]
136 fn header_contains_dims() {
137 let e = new_ptx_export(128, 64);
138 let h = build_ptx_header_string(&e);
139 assert!(h.contains("128"));
140 assert!(h.contains("64"));
141 }
142
143 #[test]
144 fn validate_valid() {
145 let e = new_ptx_export(10, 10);
146 assert!(validate_ptx(&e));
147 }
148
149 #[test]
150 fn validate_zero_dims_fails() {
151 let e = new_ptx_export(0, 0);
152 assert!(!validate_ptx(&e));
153 }
154
155 #[test]
156 fn export_string_has_point() {
157 let mut e = new_ptx_export(1, 1);
158 add_ptx_point(&mut e, 1.0, 2.0, 3.0, 0.5);
159 let s = export_ptx_string(&e);
160 assert!(s.contains("1.000000"));
161 }
162
163 #[test]
164 fn from_positions() {
165 let pos = vec![[1.0f32, 2.0, 3.0], [4.0, 5.0, 6.0]];
166 let e = ptx_from_positions(&pos);
167 assert_eq!(ptx_point_count(&e), 2);
168 }
169
170 #[test]
171 fn file_size_estimate() {
172 assert!(ptx_file_size_estimate(100) > 100);
173 }
174
175 #[test]
176 fn header_rows_correct() {
177 let e = new_ptx_export(100, 50);
178 assert_eq!(e.header.rows, 50);
179 }
180}