extern crate chrono;
extern crate las;
extern crate uuid;
use las::{Builder, Point, Reader, Writer};
use std::io::Cursor;
pub fn roundtrip(builder: Builder, point: &Point, should_succeed: bool) {
let header = if should_succeed {
builder.into_header().unwrap()
} else {
assert!(builder.into_header().is_err());
return;
};
let mut writer = Writer::new(Cursor::new(Vec::new()), header).unwrap();
writer.write_point(point.clone()).unwrap();
let header = writer.header().clone();
let mut reader = Reader::new(writer.into_inner().unwrap()).unwrap();
assert_eq!(*point, reader.read_point().unwrap().unwrap());
assert!(reader.read_point().unwrap().is_none());
assert_eq!(header, *reader.header());
}
macro_rules! roundtrip_point {
($name:ident, $modify_point:expr_2021) => {
roundtrip_point!($name, $modify_point, 0);
};
($name:ident, $modify_point:expr_2021, $min_version_minor:expr_2021) => {
roundtrip_point!($name, $modify_point, $min_version_minor, |_f| {});
};
($name:ident, $modify_point:expr_2021, $min_version_minor:expr_2021, $modify_point_format:expr_2021) => {
#[test]
fn $name() {
use las::{point::Format, Builder, Point, Version};
let version = super::version();
let should_succeed = version >= Version::new(1, $min_version_minor);
let mut point_format = Format::default();
$modify_point_format(&mut point_format);
let mut point = Point::default();
$modify_point(&mut point);
let mut builder = Builder::from(version);
builder.point_format = point_format;
crate::roundtrip(builder, &point, should_succeed);
}
};
}
macro_rules! roundtrip_builder {
($name:ident, $modify_builder:expr_2021) => {
roundtrip_builder!($name, $modify_builder, 0);
};
($name:ident, $modify_builder:expr_2021, $min_version_minor:expr_2021) => {
#[test]
fn $name() {
use las::{Builder, Point, Version};
let version = super::version();
let should_succeed = version >= Version::new(1, $min_version_minor);
let mut builder = Builder::from(version);
$modify_builder(&mut builder);
crate::roundtrip(builder, &Point::default(), should_succeed);
}
};
}
macro_rules! version {
($name:ident, $major:expr_2021, $minor:expr_2021) => {
mod $name {
use las::Version;
fn version() -> Version {
Version::new($major, $minor)
}
mod point {
use las::{
point::{Classification, ScanDirection},
Color,
};
roundtrip_point!(xyz, |p: &mut Point| {
p.x = 1.;
p.y = 2.;
p.z = 3.;
});
roundtrip_point!(intensity, |p: &mut Point| p.intensity = 42);
roundtrip_point!(return_number, |p: &mut Point| p.return_number = 2);
roundtrip_point!(number_of_returns, |p: &mut Point| p.number_of_returns = 2);
roundtrip_point!(scan_direction, |p: &mut Point| p.scan_direction =
ScanDirection::LeftToRight);
roundtrip_point!(is_edge_of_flight_line, |p: &mut Point| p
.is_edge_of_flight_line =
true);
roundtrip_point!(classification, |p: &mut Point| p.classification =
Classification::Ground);
roundtrip_point!(is_synthetic, |p: &mut Point| p.is_synthetic = true);
roundtrip_point!(is_key_point, |p: &mut Point| p.is_key_point = true);
roundtrip_point!(is_withheld, |p: &mut Point| p.is_withheld = true);
roundtrip_point!(is_overlap, |p: &mut Point| {
p.classification = Classification::Unclassified;
p.is_overlap = true;
});
roundtrip_point!(
scanner_channel,
|p: &mut Point| {
p.scanner_channel = 1;
p.gps_time = Some(42.);
},
4,
|f: &mut Format| f.extend()
);
roundtrip_point!(scan_angle_rank, |p: &mut Point| p.scan_angle = 3.);
roundtrip_point!(user_data, |p: &mut Point| p.user_data = 42);
roundtrip_point!(point_source_id, |p: &mut Point| p.point_source_id = 42);
roundtrip_point!(
gps_time,
|p: &mut Point| p.gps_time = Some(42.),
0,
|f: &mut Format| f.has_gps_time = true
);
roundtrip_point!(
color,
|p: &mut Point| p.color = Some(Color {
red: 1,
green: 2,
blue: 3
}),
2,
|f: &mut Format| f.has_color = true
);
roundtrip_point!(
nir,
|p: &mut Point| {
p.color = Some(Color {
red: 1,
green: 2,
blue: 3,
});
p.nir = Some(42);
p.gps_time = Some(42.);
},
4,
|f: &mut Format| {
f.extend();
f.has_color = true;
f.has_nir = true;
}
);
roundtrip_point!(
extra_bytes,
|p: &mut Point| p.extra_bytes = vec![42],
0,
|f: &mut Format| f.extra_bytes = 1
);
}
mod builder {
use chrono::NaiveDate;
use las::{GpsTimeType, Vlr};
use uuid::Uuid;
roundtrip_builder!(file_source_id, |b: &mut Builder| b.file_source_id = 42, 1);
roundtrip_builder!(
gps_time_type,
|b: &mut Builder| b.gps_time_type = GpsTimeType::Standard,
2
);
roundtrip_builder!(
has_synthetic_return_numbers,
|b: &mut Builder| b.has_synthetic_return_numbers = true,
3
);
roundtrip_builder!(guid, |b: &mut Builder| b.guid = Uuid::from_bytes([42; 16]));
roundtrip_builder!(system_identifier, |b: &mut Builder| b.system_identifier =
"roundtrip test".to_string());
roundtrip_builder!(generating_software, |b: &mut Builder| b
.generating_software =
"roundtrip test".to_string());
roundtrip_builder!(date, |b: &mut Builder| b.date =
NaiveDate::from_ymd_opt(2017, 10, 30));
roundtrip_builder!(transforms, |b: &mut Builder| {
use las::{Transform, Vector};
let transform = Transform {
scale: 0.1,
offset: -1.,
};
b.transforms = Vector {
x: transform,
y: transform,
z: transform,
};
});
roundtrip_builder!(vlrs, |b: &mut Builder| b.vlrs.push(Default::default()));
roundtrip_builder!(
evlrs,
|b: &mut Builder| {
let mut vlr = Vlr::default();
vlr.data = vec![42; u16::MAX as usize + 1];
b.evlrs.push(vlr);
},
4
);
roundtrip_builder!(padding, |b: &mut Builder| b.padding =
b"You probably shouldn't do this".to_vec());
roundtrip_builder!(vlr_padding, |b: &mut Builder| b.vlr_padding =
b"You probably shouldn't do this either".to_vec());
roundtrip_builder!(
point_padding,
|b: &mut Builder| {
b.point_padding = vec![42];
b.evlrs.push(Vlr::default());
},
4
);
}
}
};
}
version!(las_1_0, 1, 0);
version!(las_1_1, 1, 1);
version!(las_1_2, 1, 2);
version!(las_1_3, 1, 3);
version!(las_1_4, 1, 4);