1use byteorder::{ByteOrder, LittleEndian};
2use std::fmt;
3use std::fs::File;
4use std::io::prelude::*;
5use std::io::BufReader;
6
7pub struct PointCloud {
33 pub header: PointCloudHeader,
34 pub decompressed_buffer: Vec<u8>,
35}
36
37impl fmt::Debug for PointCloud {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 f.debug_struct("PointCloud")
40 .field("header", &self.header)
41 .field(
42 "decompressed_buffer",
43 &format!("[{} bytes buffer]", self.decompressed_buffer.len()),
44 )
45 .finish()
46 }
47}
48
49#[derive(Debug)]
50pub struct PointCloudHeader {
51 pub data_format: String,
52 pub num_points: usize,
53 pub field_names: Vec<String>,
54 pub size_list: Vec<usize>,
55 pub type_list: Vec<String>,
56}
57
58impl PointCloud {
59 pub fn from_filename(filename: &str) -> PointCloud {
60 let f = File::open(filename).expect("error reading pcd file.");
61 let mut reader = BufReader::new(&f);
62 let data_format: String;
63 let mut num_points: usize = 0;
64 let mut field_names = Vec::<String>::new();
65 let mut size_list = Vec::<usize>::new();
66 let mut type_list = Vec::<String>::new();
67
68 loop {
69 let mut line = String::new();
70 let _ = reader
71 .read_line(&mut line)
72 .expect("failed to read a line from pcd header.");
73 line = line[..line.len() - 1].to_string();
74
75 if line.starts_with("#") {
76 } else if line.starts_with("VERSION") {
77 } else if line.starts_with("FIELDS") {
78 let words: Vec<String> = line.split(" ").map(|s| s.to_string()).collect();
79 let words = &words[1..];
80 field_names = words.to_vec();
81 } else if line.starts_with("SIZE") {
82 let words: Vec<String> = line.split(" ").map(|s| s.to_string()).collect();
83 let words = &words[1..];
84 size_list = words.iter().map(|s|s.parse::<usize>().expect("entry POINTS in header has wrong format: its second term is not integer.")).collect();
85 } else if line.starts_with("TYPE") {
86 let words: Vec<String> = line.split(" ").map(|s| s.to_string()).collect();
87 let words = &words[1..];
88 type_list = words.to_vec();
89 } else if line.starts_with("COUNT") {
90 } else if line.starts_with("WIDTH") {
91 } else if line.starts_with("HEIGHT") {
92 } else if line.starts_with("VIEWPOINT") {
93 } else if line.starts_with("POINTS") {
94 let words: Vec<&str> = line.split(" ").collect();
95 if words.len() != 2 {
96 panic!("entry POINTS in header has wrong format: it consists of other than 2 words")
97 }
98 num_points = words[1].parse::<usize>().expect(
99 "entry POINTS in header has wrong format: its second term is not integer.",
100 );
101 } else if line.starts_with("DATA") {
102 let words: Vec<&str> = line.split(" ").collect();
103 if words.len() != 2 {
104 panic!(
105 "entry DATA in header has wrong format: it consists of other than 2 words"
106 )
107 }
108 if "binary_compressed" == words[1] {
109 data_format = words[1].to_string();
110 } else {
111 panic!("currently only supporting binary_compressed format.");
112 }
113 break;
114 } else {
115 panic!("unknown header entry");
116 }
117 }
118
119 let mut u32_size_buffer = vec![0u8; 4];
120 let _ = reader.read_exact(&mut u32_size_buffer);
121 let compressed_size = LittleEndian::read_u32(&u32_size_buffer) as usize;
122 let _ = reader.read_exact(&mut u32_size_buffer);
123 let uncompressed_size = LittleEndian::read_u32(&u32_size_buffer) as usize;
124
125 let mut compressed_size_buffer = vec![0u8; compressed_size];
126 let _ = reader.read_exact(&mut compressed_size_buffer);
127 let decompressed_buffer = lzf::decompress(&compressed_size_buffer, uncompressed_size)
128 .expect("error decompressing binary_comprressed pcd data.");
129 PointCloud {
130 decompressed_buffer,
131 header: PointCloudHeader {
132 data_format,
133 num_points,
134 field_names,
135 size_list,
136 type_list,
137 },
138 }
139 }
140
141 fn get_data_offset(&self, fieldname: &str, type_string: &str, item_size: usize) -> usize {
142 let mut data_offset: usize = 0;
143 for (i, fname) in self.header.field_names.iter().enumerate() {
144 if fname == fieldname {
145 if self.header.type_list[i] != type_string || self.header.size_list[i] != item_size
146 {
147 panic!(
148 "required fieldname is not a type of {}{}",
149 type_string, item_size
150 )
151 }
152 break;
153 }
154 data_offset += self.header.size_list[i];
155 }
156 data_offset
157 }
158
159 fn read_data<T>(
160 &self,
161 fieldname: &str,
162 type_string: &str,
163 item_size: usize,
164 read_buffer_fn: fn(&[u8], &mut [T]),
165 data_buffer: &mut Vec<T>,
166 ) {
167 if !self.header.field_names.contains(&fieldname.to_string()) {
168 panic!("pointcloud does not contain required fieldname");
169 }
170 let data_offset = self.get_data_offset(fieldname, type_string, item_size);
171 read_buffer_fn(
172 &self.decompressed_buffer[data_offset * self.header.num_points
173 ..(data_offset + item_size) * self.header.num_points],
174 data_buffer,
175 );
176 }
177
178 pub fn get_data_f32(&self, fieldname: &str) -> Vec<f32> {
179 let mut data_buffer = vec![0.0; self.header.num_points];
180 self.read_data::<f32>(
181 fieldname,
182 "F",
183 4,
184 LittleEndian::read_f32_into,
185 &mut data_buffer,
186 );
187 data_buffer
188 }
189
190 pub fn get_data_f64(&self, fieldname: &str) -> Vec<f64> {
191 let mut data_buffer = vec![0.0; self.header.num_points];
192 self.read_data::<f64>(
193 fieldname,
194 "F",
195 8,
196 LittleEndian::read_f64_into,
197 &mut data_buffer,
198 );
199 data_buffer
200 }
201
202 pub fn get_data_u8(&self, fieldname: &str) -> Vec<u8> {
203 let mut data_buffer = vec![0; self.header.num_points];
204 fn copy_u8_into(source: &[u8], target: &mut [u8]) {
205 target[..].clone_from_slice(source);
206 }
207 self.read_data::<u8>(fieldname, "U", 1, copy_u8_into, &mut data_buffer);
208 data_buffer
209 }
210
211 pub fn get_data_u16(&self, fieldname: &str) -> Vec<u16> {
212 let mut data_buffer = vec![0; self.header.num_points];
213 self.read_data::<u16>(
214 fieldname,
215 "U",
216 2,
217 LittleEndian::read_u16_into,
218 &mut data_buffer,
219 );
220 data_buffer
221 }
222
223 pub fn get_data_u32(&self, fieldname: &str) -> Vec<u32> {
224 let mut data_buffer = vec![0; self.header.num_points];
225 self.read_data::<u32>(
226 fieldname,
227 "U",
228 4,
229 LittleEndian::read_u32_into,
230 &mut data_buffer,
231 );
232 data_buffer
233 }
234
235 pub fn get_data_u64(&self, fieldname: &str) -> Vec<u64> {
236 let mut data_buffer = vec![0; self.header.num_points];
237 self.read_data::<u64>(
238 fieldname,
239 "U",
240 8,
241 LittleEndian::read_u64_into,
242 &mut data_buffer,
243 );
244 data_buffer
245 }
246
247 pub fn get_data_i16(&self, fieldname: &str) -> Vec<i16> {
260 let mut data_buffer = vec![0; self.header.num_points];
261 self.read_data::<i16>(
262 fieldname,
263 "I",
264 2,
265 LittleEndian::read_i16_into,
266 &mut data_buffer,
267 );
268 data_buffer
269 }
270
271 pub fn get_data_i32(&self, fieldname: &str) -> Vec<i32> {
272 let mut data_buffer = vec![0; self.header.num_points];
273 self.read_data::<i32>(
274 fieldname,
275 "I",
276 4,
277 LittleEndian::read_i32_into,
278 &mut data_buffer,
279 );
280 data_buffer
281 }
282
283 pub fn get_data_i64(&self, fieldname: &str) -> Vec<i64> {
284 let mut data_buffer = vec![0; self.header.num_points];
285 self.read_data::<i64>(
286 fieldname,
287 "I",
288 8,
289 LittleEndian::read_i64_into,
290 &mut data_buffer,
291 );
292 data_buffer
293 }
294}
295