pasture_io/las/
write_helpers.rs

1use std::{convert::TryInto, io::Write};
2
3use anyhow::Result;
4use byteorder::{LittleEndian, WriteBytesExt};
5use pasture_core::nalgebra::Vector3;
6
7use super::BitAttributes;
8
9/// Writes the given world space position as a LAS position to the given `writer`
10pub(crate) fn write_position_as_las_position<T: Write>(
11    world_space_position: &Vector3<f64>,
12    las_header: &las::raw::Header,
13    mut writer: T,
14) -> Result<()> {
15    let local_x : i32 = (((world_space_position.x - las_header.x_offset) / las_header.x_scale_factor) as i64).try_into().expect("write_position_as_las_position: Position is out of bounds given the current LAS offset and scale!");
16    let local_y : i32 = (((world_space_position.y - las_header.y_offset) / las_header.y_scale_factor) as i64).try_into().expect("write_position_as_las_position: Position is out of bounds given the current LAS offset and scale!");
17    let local_z : i32 = (((world_space_position.z - las_header.z_offset) / las_header.z_scale_factor) as i64).try_into().expect("write_position_as_las_position: Position is out of bounds given the current LAS offset and scale!");
18    writer.write_i32::<LittleEndian>(local_x)?;
19    writer.write_i32::<LittleEndian>(local_y)?;
20    writer.write_i32::<LittleEndian>(local_z)?;
21
22    Ok(())
23}
24
25/// Writes the given `BitAttributes` in LAS format to the given `writer`
26pub fn write_las_bit_attributes<T: Write>(
27    bit_attributes: BitAttributes,
28    writer: &mut T,
29) -> Result<()> {
30    match bit_attributes {
31        BitAttributes::Regular(attributes) => {
32            let mask = (attributes.return_number & 0b111)
33                | (attributes.number_of_returns & 0b111) << 3
34                | (attributes.scan_direction_flag & 0b1) << 6
35                | (attributes.edge_of_flight_line & 0b1) << 7;
36            writer.write_u8(mask)?;
37        }
38        BitAttributes::Extended(attributes) => {
39            let low_mask =
40                (attributes.return_number & 0b1111) | (attributes.number_of_returns & 0b1111) << 4;
41            let high_mask = (attributes.classification_flags & 0b1111)
42                | (attributes.scanner_channel & 0b11) << 4
43                | (attributes.scan_direction_flag & 0b1) << 6
44                | (attributes.edge_of_flight_line & 0b1) << 7;
45            writer.write_u8(low_mask)?;
46            writer.write_u8(high_mask)?;
47        }
48    }
49
50    Ok(())
51}
52
53/// Writes a Rust `str` into a LAS byte-array, since LAS encodes strings as fixed-length `u8` arrays. This copies
54/// the bytes from the Rust `str` verbatim, but might trim the `str` if it is longer than the `las_array`. Assumes
55/// that `las_array` is zero-initialized!
56pub(crate) fn write_rust_string_into_las_ascii_array<const N: usize>(
57    rust_str: &str,
58    las_array: &mut [u8; N],
59) {
60    if rust_str.as_bytes().len() >= N {
61        let dst_slice = &rust_str.as_bytes()[..N];
62        las_array.copy_from_slice(dst_slice);
63    } else {
64        let src_slice = &mut las_array[..rust_str.as_bytes().len()];
65        src_slice.copy_from_slice(rust_str.as_bytes());
66    }
67}