ros_pointcloud2/tests/e2e_test.rs

651 lines
16 KiB
Rust

use pretty_assertions::assert_eq;
use ros_pointcloud2::prelude::*;
#[cfg(feature = "derive")]
use std::fmt::Debug;
macro_rules! convert_from_into {
($point:ty, $cloud:expr) => {
convert_from_into_in_out_cloud!($cloud, $point, $cloud, $point);
};
}
macro_rules! convert_from_into_vec {
($point:ty, $cloud:expr) => {
convert_from_into_in_out_cloud_vec!($cloud, $point, $cloud, $point);
};
}
macro_rules! convert_from_into_in_out_cloud {
($in_cloud:expr, $in_point:ty, $out_cloud:expr, $out_point:ty) => {
let msg = PointCloud2Msg::try_from_iter($in_cloud.clone().into_iter());
assert!(msg.is_ok(), "{:?}", msg);
let msg = msg.unwrap();
let to_p_type = msg.try_into_iter();
assert!(to_p_type.is_ok());
let to_p_type = to_p_type.unwrap();
let back_to_type = to_p_type.collect::<Vec<$out_point>>();
let orig_cloud: Vec<$out_point> = $out_cloud.iter().cloned().collect();
assert_eq!(orig_cloud, back_to_type);
};
}
macro_rules! convert_from_into_in_out_cloud_vec {
($in_cloud:expr, $in_point:ty, $out_cloud:expr, $out_point:ty) => {
let msg = PointCloud2Msg::try_from_vec($in_cloud.clone());
assert!(msg.is_ok(), "{:?}", msg);
let msg = msg.unwrap();
let to_p_type = msg.try_into_iter();
assert!(to_p_type.is_ok());
let to_p_type = to_p_type.unwrap();
let back_to_type = to_p_type.collect::<Vec<$out_point>>();
let orig_cloud: Vec<$out_point> = $out_cloud.iter().cloned().collect();
assert_eq!(orig_cloud, back_to_type);
};
}
#[test]
fn write_cloud() {
let cloud = vec![
PointXYZ::new(0.0, 1.0, 5.0),
PointXYZ::new(1.0, 1.5, 5.0),
PointXYZ::new(1.3, 1.6, 5.7),
PointXYZ::new(f32::MAX, f32::MIN, f32::MAX),
];
let msg = PointCloud2Msg::try_from_iter(cloud);
assert!(msg.is_ok());
}
/*
#[test]
fn collect_vec() {
let cloud = vec![
PointXYZ::new(0.0, 1.0, 5.0),
PointXYZ::new(1.0, 1.5, 5.0),
PointXYZ::new(1.3, 1.6, 5.7),
PointXYZ::new(f32::MAX, f32::MIN, f32::MAX),
]
.into_iter();
let msg: Result<PointCloud2Msg, MsgConversionError> = cloud.collect();
}*/
#[test]
fn write_cloud_from_vec() {
let cloud = vec![
PointXYZ::new(0.0, 1.0, 5.0),
PointXYZ::new(1.0, 1.5, 5.0),
PointXYZ::new(1.3, 1.6, 5.7),
PointXYZ::new(f32::MAX, f32::MIN, f32::MAX),
];
let msg = PointCloud2Msg::try_from_vec(cloud);
assert!(msg.is_ok());
}
#[test]
fn write_empty_cloud_vec() {
let cloud: Vec<PointXYZ> = vec![];
let msg = PointCloud2Msg::try_from_vec(cloud);
assert!(msg.is_ok());
assert!(msg.unwrap().data.is_empty());
}
#[test]
fn write_empty_cloud_iter() {
let cloud: Vec<PointXYZ> = vec![];
let msg = PointCloud2Msg::try_from_iter(cloud);
assert!(msg.is_ok());
assert!(msg.unwrap().data.is_empty());
}
#[test]
#[cfg(feature = "rayon")]
fn conv_cloud_par_iter() {
let cloud = vec![
PointXYZ::new(0.0, 1.0, 5.0),
PointXYZ::new(1.0, 1.5, 5.0),
PointXYZ::new(1.3, 1.6, 5.7),
];
let copy = cloud.clone();
let msg: Result<PointCloud2Msg, MsgConversionError> = PointCloud2Msg::try_from_vec(cloud);
assert!(msg.is_ok());
let msg = msg.unwrap();
let to_p_type = msg.try_into_par_iter();
assert!(to_p_type.is_ok());
let to_p_type = to_p_type.unwrap();
let back_to_type = to_p_type.collect::<Vec<PointXYZ>>();
assert_eq!(copy, back_to_type);
}
#[test]
#[cfg(feature = "rayon")]
fn conv_cloud_par_par_iter() {
let cloud = vec![
PointXYZ::new(0.0, 1.0, 5.0),
PointXYZ::new(1.0, 1.5, 5.0),
PointXYZ::new(1.3, 1.6, 5.7),
PointXYZ::new(f32::MAX, f32::MIN, f32::MAX),
];
let copy = cloud.clone();
let msg = PointCloud2Msg::try_from_par_iter(cloud.into_par_iter());
assert!(msg.is_ok());
let msg = msg.unwrap();
let to_p_type = msg.try_into_par_iter();
assert!(to_p_type.is_ok());
let to_p_type = to_p_type.unwrap();
let back_to_type = to_p_type.collect::<Vec<PointXYZ>>();
assert_eq!(copy, back_to_type);
}
#[test]
#[cfg(feature = "derive")]
fn custom_xyz_f32() {
#[derive(Debug, PartialEq, Clone, Default)]
#[repr(C, align(4))]
struct CustomPoint {
x: f32,
y: f32,
z: f32,
}
impl From<RPCL2Point<3>> for CustomPoint {
fn from(point: RPCL2Point<3>) -> Self {
Self {
x: point[0].get(),
y: point[1].get(),
z: point[2].get(),
}
}
}
impl From<CustomPoint> for RPCL2Point<3> {
fn from(point: CustomPoint) -> Self {
[point.x.into(), point.y.into(), point.z.into()].into()
}
}
unsafe impl PointConvertible<3> for CustomPoint {
fn layout() -> LayoutDescription {
LayoutDescription::new(&[
LayoutField::new("x", "f32", 4),
LayoutField::new("y", "f32", 4),
LayoutField::new("z", "f32", 4),
])
}
}
convert_from_into!(
CustomPoint,
vec![
CustomPoint {
x: 1.0,
y: 2.0,
z: 3.0,
},
CustomPoint {
x: 4.0,
y: 5.0,
z: 6.0,
},
CustomPoint {
x: 7.0,
y: 8.0,
z: 9.0,
},
]
);
}
#[test]
fn custom_xyzi_f32() {
let cloud: Vec<CustomPointXYZI> = vec![
CustomPointXYZI {
x: 0.0,
y: 1.0,
z: 5.0,
i: 0,
},
CustomPointXYZI {
x: 1.0,
y: 1.5,
z: 5.0,
i: 1,
},
CustomPointXYZI {
x: 1.3,
y: 1.6,
z: 5.7,
i: 2,
},
CustomPointXYZI {
x: f32::MAX,
y: f32::MIN,
z: f32::MAX,
i: u8::MAX,
},
];
#[derive(Debug, PartialEq, Clone, Default)]
#[repr(C, align(4))]
struct CustomPointXYZI {
x: f32,
y: f32,
z: f32,
i: u8,
}
impl From<RPCL2Point<4>> for CustomPointXYZI {
fn from(point: RPCL2Point<4>) -> Self {
Self {
x: point[0].get(),
y: point[1].get(),
z: point[2].get(),
i: point[3].get(),
}
}
}
impl From<CustomPointXYZI> for RPCL2Point<4> {
fn from(point: CustomPointXYZI) -> Self {
[
point.x.into(),
point.y.into(),
point.z.into(),
point.i.into(),
]
.into()
}
}
unsafe impl PointConvertible<4> for CustomPointXYZI {
fn layout() -> LayoutDescription {
LayoutDescription::new(&[
LayoutField::new("x", "f32", 4),
LayoutField::new("y", "f32", 4),
LayoutField::new("z", "f32", 4),
LayoutField::new("i", "u8", 1),
LayoutField::padding(3),
])
}
}
convert_from_into!(CustomPointXYZI, cloud);
}
#[test]
#[cfg(feature = "derive")]
fn custom_rgba_f32() {
#[derive(Debug, PartialEq, Clone, Default)]
#[repr(C, align(4))]
struct CustomPoint {
x: f32,
y: f32,
z: f32,
r: u8,
g: u8,
b: u8,
a: u8,
}
impl From<RPCL2Point<7>> for CustomPoint {
fn from(point: RPCL2Point<7>) -> Self {
Self {
x: point[0].get(),
y: point[1].get(),
z: point[2].get(),
r: point[3].get(),
g: point[4].get(),
b: point[5].get(),
a: point[6].get(),
}
}
}
impl From<CustomPoint> for RPCL2Point<7> {
fn from(point: CustomPoint) -> Self {
[
point.x.into(),
point.y.into(),
point.z.into(),
point.r.into(),
point.g.into(),
point.b.into(),
point.a.into(),
]
.into()
}
}
unsafe impl PointConvertible<7> for CustomPoint {
fn layout() -> LayoutDescription {
LayoutDescription::new(&[
LayoutField::new("x", "f32", 4),
LayoutField::new("y", "f32", 4),
LayoutField::new("z", "f32", 4),
LayoutField::new("r", "u8", 1),
LayoutField::padding(3),
LayoutField::new("g", "u8", 1),
LayoutField::padding(3),
LayoutField::new("b", "u8", 1),
LayoutField::padding(3),
LayoutField::new("a", "u8", 1),
LayoutField::padding(3),
])
}
}
let cloud = vec![
CustomPoint {
x: 0.0,
y: 1.0,
z: 5.0,
r: 0,
g: 0,
b: 0,
a: 0,
},
CustomPoint {
x: 1.0,
y: 1.5,
z: 5.0,
r: 1,
g: 1,
b: 1,
a: 1,
},
CustomPoint {
x: 1.3,
y: 1.6,
z: 5.7,
r: 2,
g: 2,
b: 2,
a: 2,
},
CustomPoint {
x: f32::MAX,
y: f32::MIN,
z: f32::MAX,
r: u8::MAX,
g: u8::MAX,
b: u8::MAX,
a: u8::MAX,
},
];
convert_from_into!(CustomPoint, cloud);
}
#[test]
fn converterxyz() {
let cloud = vec![
PointXYZ::new(0.0, 1.0, 5.0),
PointXYZ::new(1.0, 1.5, 5.0),
PointXYZ::new(1.3, 1.6, 5.7),
PointXYZ::new(f32::MAX, f32::MIN, f32::MAX),
];
convert_from_into!(PointXYZ, cloud);
}
#[test]
fn converterxyzrgba() {
convert_from_into!(
PointXYZRGBA,
vec![
PointXYZRGBA::new(0.0, 1.0, 5.0, 0, 0, 0, 0),
PointXYZRGBA::new(1.0, 1.5, 5.0, 1, 1, 1, 1),
PointXYZRGBA::new(1.3, 1.6, 5.7, 2, 2, 2, 2),
PointXYZRGBA::new(
f32::MAX,
f32::MIN,
f32::MAX,
u8::MAX,
u8::MAX,
u8::MAX,
u8::MAX
),
]
);
}
#[test]
fn converterxyzinormal() {
convert_from_into!(
PointXYZINormal,
vec![
PointXYZINormal::new(0.0, 1.0, 5.0, 0.0, 0.0, 0.0, 0.0),
PointXYZINormal::new(1.0, 1.5, 5.0, 1.0, 1.0, 1.0, 1.0),
PointXYZINormal::new(1.3, 1.6, 5.7, 2.0, 2.0, 2.0, 2.0),
]
);
}
#[test]
fn converterxyzrgbnormal() {
convert_from_into!(
PointXYZRGBNormal,
vec![
PointXYZRGBNormal::new(0.0, 1.0, 5.0, RGB::new(0, 0, 0), 0.0, 0.0, 0.0),
PointXYZRGBNormal::new(1.0, 1.5, 5.0, RGB::new(1, 1, 1), 1.0, 1.0, 1.0),
PointXYZRGBNormal::new(1.3, 1.6, 5.7, RGB::new(2, 2, 2), 2.0, 2.0, 2.0),
PointXYZRGBNormal::new(
f32::MAX,
f32::MIN,
f32::MAX,
RGB::new(u8::MAX, u8::MAX, u8::MAX),
f32::MAX,
f32::MAX,
f32::MAX,
),
]
);
}
#[test]
fn converterxyznormal() {
convert_from_into!(
PointXYZNormal,
vec![
PointXYZNormal::new(0.0, 1.0, 5.0, 0.0, 0.0, 0.0),
PointXYZNormal::new(1.0, 1.5, 5.0, 1.0, 1.0, 1.0),
PointXYZNormal::new(1.3, 1.6, 5.7, 2.0, 2.0, 2.0),
PointXYZNormal::new(f32::MAX, f32::MIN, f32::MAX, f32::MAX, f32::MAX, f32::MAX),
]
);
}
#[test]
fn converterxyzrgbl() {
convert_from_into!(
PointXYZRGBL,
vec![
PointXYZRGBL::new(0.0, 1.0, 5.0, 0, 0, 0, 0),
PointXYZRGBL::new(1.0, 1.5, 5.0, 1, 1, 1, 1),
PointXYZRGBL::new(1.3, 1.6, 5.7, 2, 2, 2, 2),
PointXYZRGBL::new(
f32::MAX,
f32::MIN,
f32::MAX,
u8::MAX,
u8::MAX,
u8::MAX,
u32::MAX
),
]
);
}
#[test]
fn converterxyzrgb() {
convert_from_into!(
PointXYZRGB,
vec![
PointXYZRGB::new(0.0, 1.0, 5.0, 0, 0, 0),
PointXYZRGB::new(1.0, 1.5, 5.0, 1, 1, 1),
PointXYZRGB::new(1.3, 1.6, 5.7, 2, 2, 2),
PointXYZRGB::new(f32::MAX, f32::MIN, f32::MAX, u8::MAX, u8::MAX, u8::MAX),
]
);
}
#[test]
fn converterxyzrgb_from_vec() {
convert_from_into_vec!(
PointXYZRGB,
vec![
PointXYZRGB::new(0.0, 1.0, 5.0, 0, 0, 0),
PointXYZRGB::new(1.3, 1.6, 5.7, 2, 2, 2),
PointXYZRGB::new(f32::MAX, f32::MIN, f32::MAX, u8::MAX, u8::MAX, u8::MAX),
]
);
}
#[test]
fn converterxyzl() {
convert_from_into!(
PointXYZL,
vec![
PointXYZL::new(0.0, 1.0, 5.0, 0),
PointXYZL::new(1.0, 1.5, 5.0, 1),
PointXYZL::new(1.3, 1.6, 5.7, 2),
PointXYZL::new(f32::MAX, f32::MIN, f32::MAX, u32::MAX),
]
);
}
#[test]
fn converterxyzi() {
convert_from_into!(
PointXYZI,
vec![
PointXYZI::new(0.0, 1.0, 5.0, 0.0),
PointXYZI::new(1.0, 1.5, 5.0, 1.0),
PointXYZI::new(1.3, 1.6, 5.7, 2.0),
PointXYZI::new(f32::MAX, f32::MIN, f32::MAX, f32::MAX),
]
);
}
#[test]
fn write_xyzi_read_xyz() {
let write_cloud = vec![
PointXYZI::new(0.0, 1.0, 5.0, 0.0),
PointXYZI::new(1.0, 1.5, 5.0, 1.0),
PointXYZI::new(1.3, 1.6, 5.7, 2.0),
PointXYZI::new(f32::MAX, f32::MIN, f32::MAX, f32::MAX),
];
let read_cloud = [
PointXYZ::new(0.0, 1.0, 5.0),
PointXYZ::new(1.0, 1.5, 5.0),
PointXYZ::new(1.3, 1.6, 5.7),
PointXYZ::new(f32::MAX, f32::MIN, f32::MAX),
];
convert_from_into_in_out_cloud!(write_cloud, PointXYZI, read_cloud, PointXYZ);
}
#[test]
fn write_xyzi_read_xyz_vec() {
let write_cloud = vec![
PointXYZI::new(0.0, 1.0, 5.0, 0.0),
PointXYZI::new(1.0, 1.5, 5.0, 1.0),
PointXYZI::new(1.3, 1.6, 5.7, 2.0),
PointXYZI::new(f32::MAX, f32::MIN, f32::MAX, f32::MAX),
];
let read_cloud = [
PointXYZ::new(0.0, 1.0, 5.0),
PointXYZ::new(1.0, 1.5, 5.0),
PointXYZ::new(1.3, 1.6, 5.7),
PointXYZ::new(f32::MAX, f32::MIN, f32::MAX),
];
convert_from_into_in_out_cloud_vec!(write_cloud, PointXYZI, read_cloud, PointXYZ);
}
#[test]
fn write_less_than_available() {
#[derive(Debug, PartialEq, Clone, Default)]
#[repr(C, align(4))]
struct CustomPoint {
x: f32,
y: f32,
z: f32,
dummy: f32,
}
impl From<RPCL2Point<3>> for CustomPoint {
fn from(point: RPCL2Point<3>) -> Self {
Self {
x: point[0].get(),
y: point[1].get(),
z: point[2].get(),
dummy: 0.0,
}
}
}
impl From<CustomPoint> for RPCL2Point<3> {
fn from(point: CustomPoint) -> Self {
[point.x.into(), point.y.into(), point.z.into()].into()
}
}
unsafe impl PointConvertible<3> for CustomPoint {
fn layout() -> LayoutDescription {
LayoutDescription::new(&[
LayoutField::new("x", "f32", 4),
LayoutField::new("y", "f32", 4),
LayoutField::new("z", "f32", 4),
])
}
}
let write_cloud = vec![
CustomPoint {
x: 1.0,
y: 2.0,
z: 3.0,
dummy: -10.0,
},
CustomPoint {
x: 4.0,
y: 5.0,
z: 6.0,
dummy: -10.0,
},
CustomPoint {
x: 7.0,
y: 8.0,
z: 9.0,
dummy: -10.0,
},
];
let read_cloud = [
CustomPoint {
x: 1.0,
y: 2.0,
z: 3.0,
dummy: 0.0,
},
CustomPoint {
x: 4.0,
y: 5.0,
z: 6.0,
dummy: 0.0,
},
CustomPoint {
x: 7.0,
y: 8.0,
z: 9.0,
dummy: 0.0,
},
];
convert_from_into_in_out_cloud!(write_cloud, CustomPoint, read_cloud, CustomPoint);
}