1use crate::byte_source::ByteSource;
4use crate::chunk::{self, DecompressedChunk};
5use crate::error::CopcError;
6use crate::header::{self, CopcHeader, CopcInfo};
7use crate::hierarchy::{HierarchyCache, HierarchyEntry};
8use crate::types::VoxelKey;
9
10pub struct CopcStreamingReader<S: ByteSource> {
15 source: S,
16 header: CopcHeader,
17 hierarchy: HierarchyCache,
18}
19
20impl<S: ByteSource> CopcStreamingReader<S> {
21 pub async fn open(source: S) -> Result<Self, CopcError> {
23 let size = source.size().await?.unwrap_or(65536);
24 let read_size = size.min(65536);
25 let data = source.read_range(0, read_size).await?;
26 let header = header::parse_header(&data)?;
27
28 let mut hierarchy = HierarchyCache::new();
29 hierarchy.load_root(&source, &header.copc_info).await?;
30
31 Ok(Self {
32 source,
33 header,
34 hierarchy,
35 })
36 }
37
38 pub fn header(&self) -> &CopcHeader {
42 &self.header
43 }
44
45 pub fn copc_info(&self) -> &CopcInfo {
47 &self.header.copc_info
48 }
49
50 pub fn evlr_offset(&self) -> u64 {
52 self.header.evlr_offset
53 }
54
55 pub fn evlr_count(&self) -> u32 {
57 self.header.evlr_count
58 }
59
60 pub fn source(&self) -> &S {
62 &self.source
63 }
64
65 pub fn get(&self, key: &VoxelKey) -> Option<&HierarchyEntry> {
69 self.hierarchy.get(key)
70 }
71
72 pub fn entries(&self) -> impl Iterator<Item = (&VoxelKey, &HierarchyEntry)> {
74 self.hierarchy.iter()
75 }
76
77 pub fn children(&self, key: &VoxelKey) -> Vec<&HierarchyEntry> {
83 key.children()
84 .iter()
85 .filter_map(|child| self.hierarchy.get(child))
86 .collect()
87 }
88
89 pub fn node_count(&self) -> usize {
91 self.hierarchy.len()
92 }
93
94 pub fn has_pending_pages(&self) -> bool {
96 self.hierarchy.has_pending_pages()
97 }
98
99 pub async fn load_pending_pages(&mut self) -> Result<(), CopcError> {
103 self.hierarchy.load_pending_pages(&self.source).await
104 }
105
106 pub async fn load_hierarchy_for_bounds(
111 &mut self,
112 bounds: &crate::types::Aabb,
113 ) -> Result<(), CopcError> {
114 let root_bounds = self.header.copc_info.root_bounds();
115 self.hierarchy
116 .load_pages_for_bounds(&self.source, bounds, &root_bounds)
117 .await
118 }
119
120 pub async fn load_hierarchy_for_bounds_to_level(
131 &mut self,
132 bounds: &crate::types::Aabb,
133 max_level: i32,
134 ) -> Result<(), CopcError> {
135 let root_bounds = self.header.copc_info.root_bounds();
136 self.hierarchy
137 .load_pages_for_bounds_to_level(&self.source, bounds, &root_bounds, max_level)
138 .await
139 }
140
141 pub async fn load_all_hierarchy(&mut self) -> Result<(), CopcError> {
143 self.hierarchy
144 .load_all(&self.source, &self.header.copc_info)
145 .await
146 }
147
148 pub async fn fetch_chunk(&self, key: &VoxelKey) -> Result<DecompressedChunk, CopcError> {
152 self.fetch_chunk_with_source(&self.source, key).await
153 }
154
155 pub async fn fetch_chunk_with_source(
161 &self,
162 source: &impl ByteSource,
163 key: &VoxelKey,
164 ) -> Result<DecompressedChunk, CopcError> {
165 let entry = self
166 .hierarchy
167 .get(key)
168 .ok_or(CopcError::NodeNotFound(*key))?;
169 let point_record_length = self.header.las_header.point_format().len()
170 + self.header.las_header.point_format().extra_bytes;
171 chunk::fetch_and_decompress(source, entry, &self.header.laz_vlr, point_record_length).await
172 }
173
174 pub fn read_points(&self, chunk: &DecompressedChunk) -> Result<Vec<las::Point>, CopcError> {
176 chunk::read_points(chunk, &self.header.las_header)
177 }
178
179 pub fn read_points_range(
185 &self,
186 chunk: &DecompressedChunk,
187 range: std::ops::Range<u32>,
188 ) -> Result<Vec<las::Point>, CopcError> {
189 chunk::read_points_range(chunk, &self.header.las_header, range)
190 }
191
192 pub fn read_points_in_bounds(
194 &self,
195 chunk: &DecompressedChunk,
196 bounds: &crate::types::Aabb,
197 ) -> Result<Vec<las::Point>, CopcError> {
198 let points = chunk::read_points(chunk, &self.header.las_header)?;
199 Ok(filter_points_by_bounds(points, bounds))
200 }
201
202 pub fn read_points_range_in_bounds(
208 &self,
209 chunk: &DecompressedChunk,
210 range: std::ops::Range<u32>,
211 bounds: &crate::types::Aabb,
212 ) -> Result<Vec<las::Point>, CopcError> {
213 let points = chunk::read_points_range(chunk, &self.header.las_header, range)?;
214 Ok(filter_points_by_bounds(points, bounds))
215 }
216
217 pub async fn query_points(
229 &mut self,
230 bounds: &crate::types::Aabb,
231 ) -> Result<Vec<las::Point>, CopcError> {
232 self.load_hierarchy_for_bounds(bounds).await?;
233 let root_bounds = self.header.copc_info.root_bounds();
234
235 let keys: Vec<VoxelKey> = self
236 .hierarchy
237 .iter()
238 .filter(|(k, e)| e.point_count > 0 && k.bounds(&root_bounds).intersects(bounds))
239 .map(|(k, _)| *k)
240 .collect();
241
242 let mut all_points = Vec::new();
243 for key in keys {
244 let chunk = self.fetch_chunk(&key).await?;
245 let points = self.read_points_in_bounds(&chunk, bounds)?;
246 all_points.extend(points);
247 }
248 Ok(all_points)
249 }
250
251 pub async fn query_points_to_level(
261 &mut self,
262 bounds: &crate::types::Aabb,
263 max_level: i32,
264 ) -> Result<Vec<las::Point>, CopcError> {
265 self.load_hierarchy_for_bounds_to_level(bounds, max_level)
266 .await?;
267 let root_bounds = self.header.copc_info.root_bounds();
268
269 let keys: Vec<VoxelKey> = self
270 .hierarchy
271 .iter()
272 .filter(|(k, e)| {
273 e.point_count > 0
274 && k.level <= max_level
275 && k.bounds(&root_bounds).intersects(bounds)
276 })
277 .map(|(k, _)| *k)
278 .collect();
279
280 let mut all_points = Vec::new();
281 for key in keys {
282 let chunk = self.fetch_chunk(&key).await?;
283 let points = self.read_points_in_bounds(&chunk, bounds)?;
284 all_points.extend(points);
285 }
286 Ok(all_points)
287 }
288}
289
290pub fn filter_points_by_bounds(
292 points: Vec<las::Point>,
293 bounds: &crate::types::Aabb,
294) -> Vec<las::Point> {
295 points
296 .into_iter()
297 .filter(|p| {
298 p.x >= bounds.min[0]
299 && p.x <= bounds.max[0]
300 && p.y >= bounds.min[1]
301 && p.y <= bounds.max[1]
302 && p.z >= bounds.min[2]
303 && p.z <= bounds.max[2]
304 })
305 .collect()
306}