Reading LAS files

This section covers reading LAS files using pasture, including compressed LAZ files.

Reading in the default LAS point record layout

LAS and LAZ files can be read using the LASReader type. It works with a file path or any type implementing Read:

use anyhow::{bail, Context, Result};
use pasture_core::{
    containers::{BorrowedBuffer, BorrowedBufferExt, HashMapBuffer, VectorBuffer},
    layout::{attributes::POSITION_3D, PointLayout},
    nalgebra::Vector3,
};
use pasture_io::{
    base::PointReader,
    las::{LASReader, ATTRIBUTE_LOCAL_LAS_POSITION},
};

fn main() -> Result<()> {
    let args = std::env::args().collect::<Vec<_>>();
    if args.len() != 2 {
        bail!("Usage: las_io <INPUT_FILE>");
    }
    let input_file = args[1].as_str();

    let mut las_reader =
        LASReader::from_path(input_file, false).context("Could not open LAS file")?;
    let points = las_reader
        .read::<VectorBuffer>(10)
        .context("Error while reading points")?;

    for position in points
        .view_attribute::<Vector3<f64>>(&POSITION_3D)
        .into_iter()
        .take(10)
    {
        eprintln!("{}", position);
    }

    Ok(())
}

The from_path and from_read functions have a section parameter that determines the PointLayout that pasture will create for the point records within the file. If set to false, you will get a more convenient PointLayout than the raw binary layout as per the LAS specification. This includes positions as 64-bit floating-point values in world space as opposed to 32-bit signed integer values in local space, and unpacked bit attributes like the return number, number of returns etc. If you instead want a PointLayout that exactly matches the binary layout of the point record format, pass true as the second parameter to from_path and from_read!

Reading points with a custom PointLayout

If you only want to read some specific point attributes from a LAS/LAZ file, you can call read_into on the reader instead of read. This will read into a given buffer, respecting the PointLayout of the buffer:

// Imports redacted for brevity

fn main() -> Result<()> {
    let args = std::env::args().collect::<Vec<_>>();
    if args.len() != 2 {
        bail!("Usage: las_io <INPUT_FILE>");
    }
    let input_file = args[1].as_str();

    let mut las_reader = LASReader::from_path(input_file, false).context("Could not open LAS file")?;

    let layout = PointLayout::from_attributes(&[POSITION_3D]);
    let mut points = HashMapBuffer::with_capacity(10, layout);
    las_reader
        .read_into(&mut points, 10)
        .context("Can't read points in custom layout")?;

    for position in points.view_attribute::<Vector3<f64>>(&POSITION_3D).iter() {
        eprintln!("{}", position);
    }

    Ok(())
}

Reading points with a memory layout that exactly matches the binary layout of LAS point records

Lastly, here is an example for reading LAS/LAZ data with a PointLayout that matches the binary layout of the point records. The resulting buffer will not contain a POSITION_3D attribute but instead the special ATTRIBUTE_LOCAL_LAS_POSITION.

fn main() -> Result<()> {
    let args = std::env::args().collect::<Vec<_>>();
    if args.len() != 2 {
        bail!("Usage: las_io <INPUT_FILE>");
    }
    let input_file = args[1].as_str();
    
    let mut native_las_reader =
        LASReader::from_path(input_file, true).context("Could not open LAS file")?;

    let native_points = native_las_reader
        .read::<VectorBuffer>(10)
        .context("Failed to read points")?;
    eprintln!(
        "PointLayout obtained from a native LAS reader: {}",
        native_points.point_layout()
    );

    for local_position in native_points
        .view_attribute::<Vector3<i32>>(&ATTRIBUTE_LOCAL_LAS_POSITION)
        .into_iter()
    {
        eprintln!("{local_position}");
    }

    Ok(())
}