mod las;
#[cfg(feature = "laz")]
mod laz;
use crate::{Error, Header, Point, Result};
use std::{
fs::File,
io::{BufReader, Seek},
path::Path,
};
trait ReadPoints {
fn read_point(&mut self) -> Result<Option<Point>>;
fn read_points(&mut self, n: u64, points: &mut Vec<Point>) -> Result<u64>;
fn seek(&mut self, index: u64) -> Result<()>;
fn header(&self) -> &Header;
}
#[allow(missing_debug_implementations)]
pub struct PointIterator<'a> {
point_reader: &'a mut dyn ReadPoints,
}
impl Iterator for PointIterator<'_> {
type Item = Result<Point>;
fn next(&mut self) -> Option<Self::Item> {
self.point_reader.read_point().transpose()
}
}
#[deprecated(
since = "0.9.0",
note = "This interface has been refactored so that importing `Read` is no longer required"
)]
pub trait Read {
fn header(&self) -> &Header;
fn read(&mut self) -> Option<Result<Point>>;
fn read_n(&mut self, n: u64) -> Result<Vec<Point>>;
fn read_n_into(&mut self, n: u64, points: &mut Vec<Point>) -> Result<u64>;
fn read_all_points(&mut self, points: &mut Vec<Point>) -> Result<u64>;
fn seek(&mut self, position: u64) -> Result<()>;
fn points(&mut self) -> PointIterator<'_>;
}
#[cfg(feature = "laz")]
#[derive(Debug, Clone, Copy)]
pub enum LazParallelism {
#[cfg(feature = "laz-parallel")]
Yes,
No,
}
#[derive(Debug, Clone, Copy)]
pub struct ReaderOptions {
#[cfg(feature = "laz")]
laz_parallelism: LazParallelism,
}
impl ReaderOptions {
#[cfg(feature = "laz")]
pub fn with_laz_parallelism(mut self, laz_parallelism: LazParallelism) -> Self {
self.laz_parallelism = laz_parallelism;
self
}
}
impl Default for ReaderOptions {
fn default() -> Self {
#[cfg(feature = "laz-parallel")]
{
Self {
laz_parallelism: LazParallelism::Yes,
}
}
#[cfg(all(feature = "laz", not(feature = "laz-parallel")))]
{
Self {
laz_parallelism: LazParallelism::No,
}
}
#[cfg(not(feature = "laz"))]
{
Self {}
}
}
}
#[allow(missing_debug_implementations)]
pub struct Reader {
point_reader: Box<dyn ReadPoints>,
}
impl Reader {
pub fn new<R: std::io::Read + Seek + Send + Sync + 'static>(read: R) -> Result<Reader> {
Self::with_options(read, ReaderOptions::default())
}
pub fn with_options<R: std::io::Read + Seek + Send + Sync + 'static>(
mut read: R,
options: ReaderOptions,
) -> Result<Reader> {
let header = Header::new(&mut read)?;
if header.point_format().is_compressed {
#[cfg(feature = "laz")]
{
let point_reader: Box<dyn ReadPoints> = match options.laz_parallelism {
#[cfg(feature = "laz-parallel")]
LazParallelism::Yes => {
laz::PointReader::new_parallel(read, header).map(Box::new)?
}
LazParallelism::No => laz::PointReader::new(read, header).map(Box::new)?,
};
Ok(Reader { point_reader })
}
#[cfg(not(feature = "laz"))]
{
Err(Error::LaszipNotEnabled)
}
} else {
let _ = options;
Ok(Reader {
point_reader: Box::new(las::PointReader::new(read, header)?),
})
}
}
pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Reader> {
File::open(path)
.map_err(Error::from)
.and_then(|file| Reader::new(BufReader::new(file)))
}
pub fn header(&self) -> &Header {
self.point_reader.header()
}
pub fn read_point(&mut self) -> Result<Option<Point>> {
self.point_reader.read_point()
}
pub fn read_points(&mut self, n: u64) -> Result<Vec<Point>> {
let mut points = Vec::with_capacity(n.try_into()?);
let _ = self.point_reader.read_points(n, &mut points)?;
Ok(points)
}
pub fn read_points_into(&mut self, n: u64, points: &mut Vec<Point>) -> Result<u64> {
self.point_reader.read_points(n, points)
}
#[deprecated(
since = "0.9.0",
note = "Use read_point() instead, which returns a Result<Option<Point>>"
)]
pub fn read(&mut self) -> Option<Result<Point>> {
self.point_reader.read_point().transpose()
}
#[deprecated(since = "0.9.0", note = "Use read_points() instead")]
pub fn read_n(&mut self, n: u64) -> Result<Vec<Point>> {
self.read_points(n)
}
#[deprecated(since = "0.9.0", note = "Use read_points_into() instead")]
pub fn read_n_into(&mut self, n: u64, points: &mut Vec<Point>) -> Result<u64> {
self.read_points_into(n, points)
}
pub fn read_all_points_into(&mut self, points: &mut Vec<Point>) -> Result<u64> {
let point_count = self.point_reader.header().number_of_points();
self.point_reader.read_points(point_count, points)
}
#[deprecated(since = "0.9.0", note = "Use read_all_points_into() instead")]
pub fn read_all_points(&mut self, points: &mut Vec<Point>) -> Result<u64> {
self.read_all_points_into(points)
}
pub fn seek(&mut self, position: u64) -> Result<()> {
self.point_reader.seek(position)
}
pub fn points(&mut self) -> PointIterator<'_> {
PointIterator {
point_reader: &mut *self.point_reader,
}
}
}
#[allow(deprecated)]
impl Read for Reader {
fn header(&self) -> &Header {
self.header()
}
fn read(&mut self) -> Option<Result<Point>> {
self.read()
}
fn read_n(&mut self, n: u64) -> Result<Vec<Point>> {
self.read_n(n)
}
fn read_n_into(&mut self, n: u64, points: &mut Vec<Point>) -> Result<u64> {
self.read_n_into(n, points)
}
fn read_all_points(&mut self, points: &mut Vec<Point>) -> Result<u64> {
self.read_all_points(points)
}
fn seek(&mut self, position: u64) -> Result<()> {
self.seek(position)
}
fn points(&mut self) -> PointIterator<'_> {
self.points()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Writer;
#[test]
fn seek() {
let mut writer = Writer::default();
writer.write_point(Default::default()).unwrap();
let point = Point {
x: 1.,
y: 2.,
z: 3.,
..Default::default()
};
writer.write_point(point.clone()).unwrap();
let mut reader = Reader::new(writer.into_inner().unwrap()).unwrap();
reader.seek(1).unwrap();
assert_eq!(point, reader.read_point().unwrap().unwrap());
assert!(reader.read_point().unwrap().is_none());
}
}