1
1
use std:: io:: Cursor ;
2
2
3
3
use super :: super :: definitions:: sensor_msgs:: { self , PointField , PointFieldDatatype } ;
4
+ use anyhow:: Context as _;
4
5
use arrow:: {
5
6
array:: {
6
- BooleanBuilder , FixedSizeListBuilder , ListBuilder , StringBuilder , StructBuilder ,
7
- UInt8Builder , UInt32Builder ,
7
+ ArrayBuilder , BooleanBuilder , FixedSizeListBuilder , Float32Builder , Float64Builder ,
8
+ Int8Builder , Int16Builder , Int32Builder , ListBuilder , StringBuilder , StructBuilder ,
9
+ UInt8Builder , UInt16Builder , UInt32Builder ,
8
10
} ,
9
11
datatypes:: { DataType , Field , Fields } ,
10
12
} ;
11
13
use byteorder:: { BigEndian , LittleEndian , ReadBytesExt as _} ;
12
14
use re_chunk:: { Chunk , ChunkComponents , ChunkId } ;
13
15
use re_types:: {
14
- AsComponents as _, Component as _, ComponentDescriptor , SerializedComponentColumn , archetypes ,
15
- components, reflection:: ComponentDescriptorExt as _,
16
+ Archetype as _, AsComponents as _, Component as _ , ComponentDescriptor ,
17
+ SerializedComponentColumn , archetypes , components, reflection:: ComponentDescriptorExt as _,
16
18
} ;
17
19
use std:: collections:: HashMap ;
18
20
@@ -37,6 +39,8 @@ pub struct PointCloud2MessageParser {
37
39
data : FixedSizeListBuilder < ListBuilder < UInt8Builder > > ,
38
40
is_dense : FixedSizeListBuilder < BooleanBuilder > ,
39
41
42
+ points : Vec < ( String , ListBuilder < Box < dyn ArrayBuilder > > ) > ,
43
+
40
44
// We lazily create this, only if we can interpret the point cloud semantically.
41
45
// For now, this is the case if there are fields with names `x`,`y`, and `z` present.
42
46
points_3ds : Option < Vec < archetypes:: Points3D > > ,
@@ -77,11 +81,27 @@ impl PointCloud2MessageParser {
77
81
data : blob_list_builder ( num_rows) ,
78
82
is_dense : fixed_size_list_builder ( 1 , num_rows) ,
79
83
84
+ points : Default :: default ( ) ,
85
+
80
86
points_3ds : None ,
81
87
}
82
88
}
83
89
}
84
90
91
+ fn builder_from_datatype ( datatype : PointFieldDatatype ) -> Box < dyn ArrayBuilder > {
92
+ match datatype {
93
+ PointFieldDatatype :: Unknown => unreachable ! ( ) ,
94
+ PointFieldDatatype :: Int8 => Box :: new ( Int8Builder :: new ( ) ) ,
95
+ PointFieldDatatype :: UInt8 => Box :: new ( UInt8Builder :: new ( ) ) ,
96
+ PointFieldDatatype :: Int16 => Box :: new ( Int16Builder :: new ( ) ) ,
97
+ PointFieldDatatype :: UInt16 => Box :: new ( UInt16Builder :: new ( ) ) ,
98
+ PointFieldDatatype :: Int32 => Box :: new ( Int32Builder :: new ( ) ) ,
99
+ PointFieldDatatype :: UInt32 => Box :: new ( UInt32Builder :: new ( ) ) ,
100
+ PointFieldDatatype :: Float32 => Box :: new ( Float32Builder :: new ( ) ) ,
101
+ PointFieldDatatype :: Float64 => Box :: new ( Float64Builder :: new ( ) ) ,
102
+ }
103
+ }
104
+
85
105
fn access ( data : & [ u8 ] , datatype : PointFieldDatatype , is_big_endian : bool ) -> std:: io:: Result < f32 > {
86
106
let mut rdr = Cursor :: new ( data) ;
87
107
match ( is_big_endian, datatype) {
@@ -103,6 +123,22 @@ fn access(data: &[u8], datatype: PointFieldDatatype, is_big_endian: bool) -> std
103
123
}
104
124
}
105
125
126
+ impl From < PointFieldDatatype > for DataType {
127
+ fn from ( value : PointFieldDatatype ) -> Self {
128
+ match value {
129
+ PointFieldDatatype :: Unknown => unreachable ! ( ) , // Not part of the MCAP spec
130
+ PointFieldDatatype :: Int8 => Self :: Int8 ,
131
+ PointFieldDatatype :: UInt8 => Self :: UInt8 ,
132
+ PointFieldDatatype :: Int16 => Self :: Int16 ,
133
+ PointFieldDatatype :: UInt16 => Self :: UInt16 ,
134
+ PointFieldDatatype :: Int32 => Self :: Int32 ,
135
+ PointFieldDatatype :: UInt32 => Self :: UInt32 ,
136
+ PointFieldDatatype :: Float32 => Self :: Float32 ,
137
+ PointFieldDatatype :: Float64 => Self :: Float64 ,
138
+ }
139
+ }
140
+ }
141
+
106
142
pub struct Position3DIter < ' a > {
107
143
point_iter : std:: slice:: ChunksExact < ' a , u8 > ,
108
144
is_big_endian : bool ,
@@ -169,6 +205,128 @@ impl Iterator for Position3DIter<'_> {
169
205
}
170
206
}
171
207
208
+ fn add_field_value (
209
+ builder : & mut Box < dyn ArrayBuilder > ,
210
+ field : & PointField ,
211
+ is_big_endian : bool ,
212
+ data : & [ u8 ] ,
213
+ ) -> anyhow:: Result < ( ) > {
214
+ let mut rdr = Cursor :: new ( data) ;
215
+ match field. datatype {
216
+ PointFieldDatatype :: Unknown => unreachable ! ( ) ,
217
+ PointFieldDatatype :: Int8 => {
218
+ let builder = builder
219
+ . as_any_mut ( )
220
+ . downcast_mut :: < Int8Builder > ( )
221
+ . with_context ( || {
222
+ format ! ( "found datatype {:?}, but `Int8Builder`" , field. datatype)
223
+ } ) ?;
224
+ let val = rdr. read_i8 ( ) ?;
225
+ builder. append_value ( val) ;
226
+ }
227
+ PointFieldDatatype :: UInt8 => {
228
+ let builder = builder
229
+ . as_any_mut ( )
230
+ . downcast_mut :: < UInt8Builder > ( )
231
+ . with_context ( || {
232
+ format ! ( "found datatype {:?}, but `UInt8Builder`" , field. datatype)
233
+ } ) ?;
234
+ let val = rdr. read_u8 ( ) ?;
235
+ builder. append_value ( val) ;
236
+ }
237
+ PointFieldDatatype :: Int16 => {
238
+ let builder = builder
239
+ . as_any_mut ( )
240
+ . downcast_mut :: < Int16Builder > ( )
241
+ . with_context ( || {
242
+ format ! ( "found datatype {:?}, but `Int16Builder`" , field. datatype)
243
+ } ) ?;
244
+ let val = if is_big_endian {
245
+ rdr. read_i16 :: < BigEndian > ( ) ?
246
+ } else {
247
+ rdr. read_i16 :: < LittleEndian > ( ) ?
248
+ } ;
249
+ builder. append_value ( val) ;
250
+ }
251
+ PointFieldDatatype :: UInt16 => {
252
+ let builder = builder
253
+ . as_any_mut ( )
254
+ . downcast_mut :: < UInt16Builder > ( )
255
+ . with_context ( || {
256
+ format ! ( "found datatype {:?}, but `UInt16Builder`" , field. datatype)
257
+ } ) ?;
258
+ let val = if is_big_endian {
259
+ rdr. read_u16 :: < BigEndian > ( ) ?
260
+ } else {
261
+ rdr. read_u16 :: < LittleEndian > ( ) ?
262
+ } ;
263
+ builder. append_value ( val) ;
264
+ }
265
+
266
+ PointFieldDatatype :: Int32 => {
267
+ let builder = builder
268
+ . as_any_mut ( )
269
+ . downcast_mut :: < Int32Builder > ( )
270
+ . with_context ( || {
271
+ format ! ( "found datatype {:?}, but `Int32Builder`" , field. datatype)
272
+ } ) ?;
273
+
274
+ let val = if is_big_endian {
275
+ rdr. read_i32 :: < BigEndian > ( ) ?
276
+ } else {
277
+ rdr. read_i32 :: < LittleEndian > ( ) ?
278
+ } ;
279
+ builder. append_value ( val) ;
280
+ }
281
+ PointFieldDatatype :: UInt32 => {
282
+ let builder = builder
283
+ . as_any_mut ( )
284
+ . downcast_mut :: < UInt32Builder > ( )
285
+ . with_context ( || {
286
+ format ! ( "found datatype {:?}, but `UInt16Builder`" , field. datatype)
287
+ } ) ?;
288
+ let val = if is_big_endian {
289
+ rdr. read_u32 :: < BigEndian > ( ) ?
290
+ } else {
291
+ rdr. read_u32 :: < LittleEndian > ( ) ?
292
+ } ;
293
+ builder. append_value ( val) ;
294
+ }
295
+
296
+ PointFieldDatatype :: Float32 => {
297
+ let builder = builder
298
+ . as_any_mut ( )
299
+ . downcast_mut :: < Float32Builder > ( )
300
+ . with_context ( || {
301
+ format ! ( "found datatype {:?}, but `Float32Builder`" , field. datatype)
302
+ } ) ?;
303
+ let val = if is_big_endian {
304
+ rdr. read_f32 :: < BigEndian > ( ) ?
305
+ } else {
306
+ rdr. read_f32 :: < LittleEndian > ( ) ?
307
+ } ;
308
+ builder. append_value ( val) ;
309
+ }
310
+
311
+ PointFieldDatatype :: Float64 => {
312
+ let builder = builder
313
+ . as_any_mut ( )
314
+ . downcast_mut :: < Float64Builder > ( )
315
+ . with_context ( || {
316
+ format ! ( "found datatype {:?}, but `Float64Builder`" , field. datatype)
317
+ } ) ?;
318
+ let val = if is_big_endian {
319
+ rdr. read_f64 :: < BigEndian > ( ) ?
320
+ } else {
321
+ rdr. read_f64 :: < LittleEndian > ( ) ?
322
+ } ;
323
+ builder. append_value ( val) ;
324
+ }
325
+ }
326
+
327
+ Ok ( ( ) )
328
+ }
329
+
172
330
impl MessageParser for PointCloud2MessageParser {
173
331
fn append ( & mut self , ctx : & mut ParserContext , msg : & mcap:: Message < ' _ > ) -> anyhow:: Result < ( ) > {
174
332
let point_cloud = cdr:: try_decode_message :: < sensor_msgs:: PointCloud2 > ( msg. data . as_ref ( ) )
@@ -191,6 +349,8 @@ impl MessageParser for PointCloud2MessageParser {
191
349
data,
192
350
is_dense,
193
351
352
+ points,
353
+
194
354
points_3ds,
195
355
} = self ;
196
356
@@ -204,6 +364,31 @@ impl MessageParser for PointCloud2MessageParser {
204
364
& point_cloud. fields ,
205
365
) ;
206
366
367
+ // We lazily initialize the builders for the values in the point cloud.
368
+ if points. len ( ) != point_cloud. fields . len ( ) {
369
+ * points = point_cloud
370
+ . fields
371
+ . iter ( )
372
+ . map ( |field| {
373
+ (
374
+ field. name . clone ( ) ,
375
+ ListBuilder :: new ( builder_from_datatype ( field. datatype ) ) ,
376
+ )
377
+ } )
378
+ . collect ( ) ;
379
+ }
380
+
381
+ for point in point_cloud. data . chunks ( point_cloud. point_step as usize ) {
382
+ for ( field, ( _name, builder) ) in point_cloud. fields . iter ( ) . zip ( points. iter_mut ( ) ) {
383
+ let field_builder = builder. values ( ) ;
384
+ add_field_value ( field_builder, field, point_cloud. is_bigendian , point) ?;
385
+ }
386
+ }
387
+
388
+ for ( _name, builder) in points {
389
+ builder. append ( true ) ;
390
+ }
391
+
207
392
if let Some ( position_iter) = position_iter {
208
393
points_3ds
209
394
. get_or_insert_with ( || Vec :: with_capacity ( * num_rows) )
@@ -287,12 +472,14 @@ impl MessageParser for PointCloud2MessageParser {
287
472
mut data,
288
473
mut is_dense,
289
474
475
+ points,
476
+
290
477
points_3ds,
291
478
} = * self ;
292
479
293
480
let mut chunks = Vec :: new ( ) ;
294
481
295
- for ( i, points_3d) in points_3ds. into_iter ( ) . enumerate ( ) {
482
+ for ( i, points_3d) in points_3ds. iter ( ) . enumerate ( ) {
296
483
let timelines = timelines
297
484
. iter ( )
298
485
. map ( |( timeline, time_col) | ( * timeline, time_col. row_sliced ( i, 1 ) . clone ( ) ) )
@@ -362,6 +549,18 @@ impl MessageParser for PointCloud2MessageParser {
362
549
) ,
363
550
]
364
551
. into_iter ( )
552
+ . chain ( points. into_iter ( ) . filter_map ( |( name, mut builder) | {
553
+ points_3ds. as_ref ( ) ?;
554
+ if [ "x" , "y" , "z" ] . contains ( & name. as_str ( ) ) {
555
+ None
556
+ } else {
557
+ Some ( (
558
+ ComponentDescriptor :: partial ( name. clone ( ) )
559
+ . with_builtin_archetype ( archetypes:: Points3D :: name ( ) ) ,
560
+ builder. finish ( ) ,
561
+ ) )
562
+ }
563
+ } ) )
365
564
. collect ( ) ,
366
565
) ?;
367
566
0 commit comments