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 node_count(&self) -> usize {
79 self.hierarchy.len()
80 }
81
82 pub fn has_pending_pages(&self) -> bool {
84 self.hierarchy.has_pending_pages()
85 }
86
87 pub async fn load_pending_pages(&mut self) -> Result<(), CopcError> {
91 self.hierarchy.load_pending_pages(&self.source).await
92 }
93
94 pub async fn load_all_hierarchy(&mut self) -> Result<(), CopcError> {
96 self.hierarchy
97 .load_all(&self.source, &self.header.copc_info)
98 .await
99 }
100
101 pub async fn fetch_chunk(&self, key: &VoxelKey) -> Result<DecompressedChunk, CopcError> {
105 let entry = self
106 .hierarchy
107 .get(key)
108 .ok_or(CopcError::Io(std::io::Error::new(
109 std::io::ErrorKind::NotFound,
110 "node not in hierarchy",
111 )))?;
112 let point_record_length = self.header.las_header.point_format().len()
113 + self.header.las_header.point_format().extra_bytes;
114 chunk::fetch_and_decompress(
115 &self.source,
116 entry,
117 &self.header.laz_vlr,
118 point_record_length,
119 )
120 .await
121 }
122
123 pub fn read_points(&self, chunk: &DecompressedChunk) -> Result<Vec<las::Point>, CopcError> {
125 chunk::read_points(chunk, &self.header.las_header)
126 }
127}