epoint_io/las/
read.rs

1use crate::las::read_impl::import_point_cloud_from_las_reader;
2use crate::{Error, FILE_EXTENSION_LAS_FORMAT, FILE_EXTENSION_LAZ_FORMAT};
3
4use crate::las::LasVersion;
5use epoint_core::PointCloud;
6
7use crate::Error::{InvalidFileExtension, NoFileExtension};
8use ecoord::FrameId;
9use ecoord::io::EcoordReader;
10use std::fmt::Debug;
11use std::fs::File;
12use std::io::{Read, Seek};
13use std::path::Path;
14
15/// `LasReader` imports a point cloud from a LAS or LAZ file.
16///
17#[derive(Debug, Clone)]
18pub struct LasReader<R: Read + Seek + Send + Debug> {
19    reader: R,
20    sidecar_ecoord_reader: Option<EcoordReader<R>>,
21    normalize_colors: bool,
22    reference_frame_id: FrameId,
23    points_per_chunk: Option<u64>,
24}
25
26impl<R: Read + Seek + Send + 'static + Debug> LasReader<R> {
27    /// Create a new [`LasReader`] from an existing `Reader`.
28    pub fn new(reader: R) -> Self {
29        Self {
30            reader,
31            sidecar_ecoord_reader: None,
32            normalize_colors: false,
33            reference_frame_id: FrameId::global(),
34            points_per_chunk: Some(100_000_000),
35        }
36    }
37
38    pub fn normalize_colors(mut self, normalize_colors: bool) -> Self {
39        self.normalize_colors = normalize_colors;
40        self
41    }
42
43    pub fn with_sidecar_ecoord_reader(mut self, reader: Option<EcoordReader<R>>) -> Self {
44        self.sidecar_ecoord_reader = reader;
45        self
46    }
47
48    pub fn with_points_per_chunk(mut self, points_per_chunk: Option<u64>) -> Self {
49        self.points_per_chunk = points_per_chunk;
50        self
51    }
52
53    pub fn finish(self) -> Result<(PointCloud, LasReadInfo), Error> {
54        let (mut point_cloud, read_info) = import_point_cloud_from_las_reader(
55            self.reader,
56            self.normalize_colors,
57            self.reference_frame_id,
58            self.points_per_chunk,
59        )?;
60
61        if let Some(reader) = self.sidecar_ecoord_reader {
62            let transform_tree = reader.finish()?;
63            point_cloud.append_transform_tree(transform_tree)?;
64        }
65
66        Ok((point_cloud, read_info))
67    }
68}
69
70impl LasReader<File> {
71    pub fn from_path(path: impl AsRef<Path>) -> Result<Self, Error> {
72        let extension = path.as_ref().extension().ok_or(NoFileExtension())?;
73        if extension != FILE_EXTENSION_LAS_FORMAT && extension != FILE_EXTENSION_LAZ_FORMAT {
74            return Err(InvalidFileExtension(
75                extension.to_str().unwrap_or_default().to_string(),
76            ));
77        }
78
79        // read sidecar ecoord file if available
80        let sidecar_ecoord_reader = EcoordReader::from_base_path(
81            path.as_ref().parent().unwrap(),
82            path.as_ref().file_stem().unwrap().to_str().unwrap(),
83        )?;
84
85        let file = File::open(path)?;
86        let las_reader = Self::new(file).with_sidecar_ecoord_reader(sidecar_ecoord_reader);
87
88        Ok(las_reader)
89    }
90}
91
92#[derive(Debug, Clone, PartialEq, Eq)]
93pub struct LasReadInfo {
94    pub version: LasVersion,
95}