Skip to content

Commit 039b4f4

Browse files
committed
Initial commit
almost working more cleanup merge race and lint
1 parent 70b3256 commit 039b4f4

File tree

1 file changed

+204
-5
lines changed

1 file changed

+204
-5
lines changed

crates/utils/re_mcap/src/parsers/ros2msg/sensor_msgs/point_cloud_2.rs

Lines changed: 204 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
use std::io::Cursor;
22

33
use super::super::definitions::sensor_msgs::{self, PointField, PointFieldDatatype};
4+
use anyhow::Context as _;
45
use arrow::{
56
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,
810
},
911
datatypes::{DataType, Field, Fields},
1012
};
1113
use byteorder::{BigEndian, LittleEndian, ReadBytesExt as _};
1214
use re_chunk::{Chunk, ChunkComponents, ChunkId};
1315
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 _,
1618
};
1719
use std::collections::HashMap;
1820

@@ -37,6 +39,8 @@ pub struct PointCloud2MessageParser {
3739
data: FixedSizeListBuilder<ListBuilder<UInt8Builder>>,
3840
is_dense: FixedSizeListBuilder<BooleanBuilder>,
3941

42+
points: Vec<(String, ListBuilder<Box<dyn ArrayBuilder>>)>,
43+
4044
// We lazily create this, only if we can interpret the point cloud semantically.
4145
// For now, this is the case if there are fields with names `x`,`y`, and `z` present.
4246
points_3ds: Option<Vec<archetypes::Points3D>>,
@@ -77,11 +81,27 @@ impl PointCloud2MessageParser {
7781
data: blob_list_builder(num_rows),
7882
is_dense: fixed_size_list_builder(1, num_rows),
7983

84+
points: Default::default(),
85+
8086
points_3ds: None,
8187
}
8288
}
8389
}
8490

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+
85105
fn access(data: &[u8], datatype: PointFieldDatatype, is_big_endian: bool) -> std::io::Result<f32> {
86106
let mut rdr = Cursor::new(data);
87107
match (is_big_endian, datatype) {
@@ -103,6 +123,22 @@ fn access(data: &[u8], datatype: PointFieldDatatype, is_big_endian: bool) -> std
103123
}
104124
}
105125

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+
106142
pub struct Position3DIter<'a> {
107143
point_iter: std::slice::ChunksExact<'a, u8>,
108144
is_big_endian: bool,
@@ -169,6 +205,128 @@ impl Iterator for Position3DIter<'_> {
169205
}
170206
}
171207

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+
172330
impl MessageParser for PointCloud2MessageParser {
173331
fn append(&mut self, ctx: &mut ParserContext, msg: &mcap::Message<'_>) -> anyhow::Result<()> {
174332
let point_cloud = cdr::try_decode_message::<sensor_msgs::PointCloud2>(msg.data.as_ref())
@@ -191,6 +349,8 @@ impl MessageParser for PointCloud2MessageParser {
191349
data,
192350
is_dense,
193351

352+
points,
353+
194354
points_3ds,
195355
} = self;
196356

@@ -204,6 +364,31 @@ impl MessageParser for PointCloud2MessageParser {
204364
&point_cloud.fields,
205365
);
206366

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+
207392
if let Some(position_iter) = position_iter {
208393
points_3ds
209394
.get_or_insert_with(|| Vec::with_capacity(*num_rows))
@@ -287,12 +472,14 @@ impl MessageParser for PointCloud2MessageParser {
287472
mut data,
288473
mut is_dense,
289474

475+
points,
476+
290477
points_3ds,
291478
} = *self;
292479

293480
let mut chunks = Vec::new();
294481

295-
for (i, points_3d) in points_3ds.into_iter().enumerate() {
482+
for (i, points_3d) in points_3ds.iter().enumerate() {
296483
let timelines = timelines
297484
.iter()
298485
.map(|(timeline, time_col)| (*timeline, time_col.row_sliced(i, 1).clone()))
@@ -362,6 +549,18 @@ impl MessageParser for PointCloud2MessageParser {
362549
),
363550
]
364551
.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+
}))
365564
.collect(),
366565
)?;
367566

0 commit comments

Comments
 (0)