use std::{
fs::File,
io::{BufReader, Read, Seek},
};
use std::{io::SeekFrom, path::Path};
use anyhow::Result;
use las_rs::Header;
use crate::base::{PointReader, SeekToPoint};
use pasture_core::{containers::BorrowedMutBuffer, layout::PointLayout, meta::Metadata};
use super::{path_is_compressed_las_file, LASMetadata, LASReaderBase, RawLASReader, RawLAZReader};
pub enum LASReaderFlavor<'a, T: Read + Seek + Send + 'a> {
LAS(RawLASReader<T>),
LAZ(RawLAZReader<'a, T>),
}
impl<'a, T: Read + Seek + Send + 'a> LASReaderFlavor<'a, T> {
pub fn remaining_points(&self) -> usize {
match self {
LASReaderFlavor::LAS(reader) => reader.remaining_points(),
LASReaderFlavor::LAZ(reader) => reader.remaining_points(),
}
}
pub fn header(&self) -> &Header {
match self {
LASReaderFlavor::LAS(reader) => reader.header(),
LASReaderFlavor::LAZ(reader) => reader.header(),
}
}
}
impl<'a, T: Read + Seek + Send + 'a> PointReader for LASReaderFlavor<'a, T> {
fn read_into<'b, 'c, B: BorrowedMutBuffer<'b>>(
&mut self,
point_buffer: &'c mut B,
count: usize,
) -> Result<usize>
where
'b: 'c,
{
match self {
LASReaderFlavor::LAS(reader) => reader.read_into(point_buffer, count),
LASReaderFlavor::LAZ(reader) => reader.read_into(point_buffer, count),
}
}
fn get_metadata(&self) -> &dyn Metadata {
match self {
LASReaderFlavor::LAS(reader) => reader.get_metadata(),
LASReaderFlavor::LAZ(reader) => reader.get_metadata(),
}
}
fn get_default_point_layout(&self) -> &PointLayout {
match self {
LASReaderFlavor::LAS(reader) => reader.get_default_point_layout(),
LASReaderFlavor::LAZ(reader) => reader.get_default_point_layout(),
}
}
}
impl<'a, T: Read + Seek + Send + 'a> SeekToPoint for LASReaderFlavor<'a, T> {
fn seek_point(&mut self, position: SeekFrom) -> Result<usize> {
match self {
LASReaderFlavor::LAS(reader) => reader.seek_point(position),
LASReaderFlavor::LAZ(reader) => reader.seek_point(position),
}
}
}
pub struct LASReader<'a, R: Read + Seek + Send + 'a> {
raw_reader: LASReaderFlavor<'a, R>,
}
impl LASReader<'static, BufReader<File>> {
pub fn from_path<P: AsRef<Path>>(
path: P,
point_layout_matches_memory_layout: bool,
) -> Result<LASReader<'static, BufReader<File>>> {
let is_compressed = path_is_compressed_las_file(path.as_ref())?;
let file = BufReader::new(File::open(path)?);
Self::from_read(file, is_compressed, point_layout_matches_memory_layout)
}
}
impl<'a, R: Read + Seek + Send> LASReader<'a, R> {
pub fn from_read(
read: R,
is_compressed: bool,
point_layout_matches_memory_layout: bool,
) -> Result<Self> {
let raw_reader = if is_compressed {
LASReaderFlavor::LAZ(RawLAZReader::from_read(
read,
point_layout_matches_memory_layout,
)?)
} else {
LASReaderFlavor::LAS(RawLASReader::from_read(
read,
point_layout_matches_memory_layout,
)?)
};
Ok(Self { raw_reader })
}
pub fn remaining_points(&self) -> usize {
self.raw_reader.remaining_points()
}
pub fn header(&self) -> &Header {
self.raw_reader.header()
}
pub fn las_metadata(&self) -> &LASMetadata {
match &self.raw_reader {
LASReaderFlavor::LAS(reader) => reader.las_metadata(),
LASReaderFlavor::LAZ(reader) => reader.las_metadata(),
}
}
}
impl<'a, R: Read + Seek + Send + 'a> PointReader for LASReader<'a, R> {
fn get_metadata(&self) -> &dyn Metadata {
self.raw_reader.get_metadata()
}
fn get_default_point_layout(&self) -> &PointLayout {
self.raw_reader.get_default_point_layout()
}
fn read_into<'b, 'c, B: BorrowedMutBuffer<'b>>(
&mut self,
point_buffer: &'c mut B,
count: usize,
) -> Result<usize>
where
'b: 'c,
{
self.raw_reader.read_into(point_buffer, count)
}
}
impl<'a, R: Read + Seek + Send + 'a> SeekToPoint for LASReader<'a, R> {
fn seek_point(&mut self, position: SeekFrom) -> Result<usize> {
self.raw_reader.seek_point(position)
}
}