1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
use std::{collections::HashMap, path::Path};
use anyhow::{anyhow, Result};
use las_rs::Builder;
use crate::las::{LASReader, LASWriter};
use super::{PointReader, PointWriter, SeekToPoint};
pub trait PointReadAndSeek: PointReader + SeekToPoint {}
impl<T: PointReader + SeekToPoint> PointReadAndSeek for T {}
type ReaderFactoryFn = dyn Fn(&Path) -> Result<Box<dyn PointReadAndSeek>>;
type WriterFactoryFn = dyn Fn(&Path) -> Result<Box<dyn PointWriter>>;
pub struct IOFactory {
reader_factories: HashMap<&'static str, Box<ReaderFactoryFn>>,
writer_factories: HashMap<&'static str, Box<WriterFactoryFn>>,
}
impl IOFactory {
pub fn make_reader(&self, file: &Path) -> Result<Box<dyn PointReadAndSeek>> {
let extension = file.extension().ok_or_else(|| {
anyhow!(
"File extension could not be determined from path {}",
file.display()
)
})?;
let extension_str = extension.to_str().ok_or_else(|| {
anyhow!(
"File extension of path {} is no valid Unicode string",
file.display()
)
})?;
let factory = self.reader_factories.get(extension_str).ok_or_else(|| {
anyhow!(
"Reading from point cloud files with extension {} is not supported",
extension_str
)
})?;
factory(file)
}
pub fn make_writer(&self, file: &Path) -> Result<Box<dyn PointWriter>> {
let extension = file.extension().ok_or_else(|| {
anyhow!(
"File extension could not be determined from path {}",
file.display()
)
})?;
let extension_str = extension.to_str().ok_or_else(|| {
anyhow!(
"File extension of path {} is no valid Unicode string",
file.display()
)
})?;
let factory = self.writer_factories.get(extension_str).ok_or_else(|| {
anyhow!(
"Writing to point cloud files with extension {} is not supported",
extension_str
)
})?;
factory(file)
}
pub fn supports_reading_from(&self, extension: &'static str) -> bool {
self.reader_factories.contains_key(extension)
}
pub fn supports_writing_to(&self, extension: &'static str) -> bool {
self.writer_factories.contains_key(extension)
}
pub fn register_reader_for_extension<
F: Fn(&Path) -> Result<Box<dyn PointReadAndSeek>> + 'static,
>(
&mut self,
extension: &'static str,
reader_factory: F,
) -> Option<Box<ReaderFactoryFn>> {
self.reader_factories
.insert(extension, Box::new(reader_factory))
}
pub fn register_writer_for_extension<F: Fn(&Path) -> Result<Box<dyn PointWriter>> + 'static>(
&mut self,
extension: &'static str,
writer_factory: F,
) -> Option<Box<WriterFactoryFn>> {
self.writer_factories
.insert(extension, Box::new(writer_factory))
}
}
impl Default for IOFactory {
fn default() -> Self {
let mut factory = Self {
reader_factories: Default::default(),
writer_factories: Default::default(),
};
factory.register_reader_for_extension("las", |path| {
let reader = LASReader::from_path(path)?;
Ok(Box::new(reader))
});
factory.register_writer_for_extension("las", |path| {
let header = Builder::from((1, 4)).into_header()?;
let writer = LASWriter::from_path_and_header(path, header)?;
Ok(Box::new(writer))
});
factory.register_reader_for_extension("laz", |path| {
let reader = LASReader::from_path(path)?;
Ok(Box::new(reader))
});
factory.register_writer_for_extension("laz", |path| {
let header = Builder::from((1, 4)).into_header()?;
let writer = LASWriter::from_path_and_header(path, header)?;
Ok(Box::new(writer))
});
factory
}
}