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#[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 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 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}