1use std::collections::HashMap;
6use std::io::Cursor;
7
8use crate::types::VoxelKey;
9use byteorder::{LittleEndian, ReadBytesExt};
10
11use crate::byte_source::ByteSource;
12use crate::error::CopcError;
13use crate::header::CopcInfo;
14
15#[derive(Debug, Clone)]
20#[non_exhaustive]
21pub struct HierarchyEntry {
22 pub key: VoxelKey,
24 pub offset: u64,
26 pub byte_size: u32,
28 pub point_count: u32,
30}
31
32#[derive(Debug, Clone)]
34struct PendingPage {
35 offset: u64,
36 size: u64,
37}
38
39pub struct HierarchyCache {
41 entries: HashMap<VoxelKey, HierarchyEntry>,
43 pending_pages: Vec<PendingPage>,
45 root_loaded: bool,
47}
48
49impl Default for HierarchyCache {
50 fn default() -> Self {
51 Self::new()
52 }
53}
54
55impl HierarchyCache {
56 pub fn new() -> Self {
58 Self {
59 entries: HashMap::new(),
60 pending_pages: Vec::new(),
61 root_loaded: false,
62 }
63 }
64
65 pub async fn load_root(
67 &mut self,
68 source: &impl ByteSource,
69 info: &CopcInfo,
70 ) -> Result<(), CopcError> {
71 if self.root_loaded {
72 return Ok(());
73 }
74 let data = source
75 .read_range(info.root_hier_offset, info.root_hier_size)
76 .await?;
77 self.parse_page(&data, info.root_hier_offset)?;
78 self.root_loaded = true;
79 Ok(())
80 }
81
82 pub async fn load_pending_pages(&mut self, source: &impl ByteSource) -> Result<(), CopcError> {
84 if self.pending_pages.is_empty() {
85 return Ok(());
86 }
87 let pages: Vec<_> = self.pending_pages.drain(..).collect();
88 let ranges: Vec<_> = pages.iter().map(|p| (p.offset, p.size)).collect();
89 let results = source.read_ranges(&ranges).await?;
90
91 for (page, data) in pages.iter().zip(results) {
92 self.parse_page(&data, page.offset)?;
93 }
94
95 Ok(())
96 }
97
98 pub async fn load_all(
100 &mut self,
101 source: &impl ByteSource,
102 info: &CopcInfo,
103 ) -> Result<(), CopcError> {
104 self.load_root(source, info).await?;
105
106 while !self.pending_pages.is_empty() {
107 self.load_pending_pages(source).await?;
108 }
109
110 Ok(())
111 }
112
113 pub fn has_pending_pages(&self) -> bool {
115 !self.pending_pages.is_empty()
116 }
117
118 pub fn get(&self, key: &VoxelKey) -> Option<&HierarchyEntry> {
120 self.entries.get(key)
121 }
122
123 pub fn iter(&self) -> impl Iterator<Item = (&VoxelKey, &HierarchyEntry)> {
125 self.entries.iter()
126 }
127
128 pub fn len(&self) -> usize {
130 self.entries.len()
131 }
132
133 pub fn is_empty(&self) -> bool {
135 self.entries.is_empty()
136 }
137
138 fn parse_page(&mut self, data: &[u8], _base_offset: u64) -> Result<(), CopcError> {
140 let entry_size = 32; let mut r = Cursor::new(data);
142
143 while (r.position() as usize + entry_size) <= data.len() {
144 let level = r.read_i32::<LittleEndian>()?;
145 let x = r.read_i32::<LittleEndian>()?;
146 let y = r.read_i32::<LittleEndian>()?;
147 let z = r.read_i32::<LittleEndian>()?;
148 let offset = r.read_u64::<LittleEndian>()?;
149 let byte_size = r.read_i32::<LittleEndian>()?;
150 let point_count = r.read_i32::<LittleEndian>()?;
151
152 let key = VoxelKey { level, x, y, z };
153
154 if point_count == -1 {
155 self.pending_pages.push(PendingPage {
157 offset,
158 size: byte_size as u64,
159 });
160 } else if point_count >= 0 && byte_size >= 0 {
161 self.entries.insert(
162 key,
163 HierarchyEntry {
164 key,
165 offset,
166 byte_size: byte_size as u32,
167 point_count: point_count as u32,
168 },
169 );
170 }
171 }
173
174 Ok(())
175 }
176}
177
178#[cfg(test)]
179mod tests {
180 use super::*;
181 use byteorder::WriteBytesExt;
182
183 fn write_hierarchy_entry(
184 buf: &mut Vec<u8>,
185 level: i32,
186 x: i32,
187 y: i32,
188 z: i32,
189 offset: u64,
190 byte_size: i32,
191 point_count: i32,
192 ) {
193 buf.write_i32::<LittleEndian>(level).unwrap();
194 buf.write_i32::<LittleEndian>(x).unwrap();
195 buf.write_i32::<LittleEndian>(y).unwrap();
196 buf.write_i32::<LittleEndian>(z).unwrap();
197 buf.write_u64::<LittleEndian>(offset).unwrap();
198 buf.write_i32::<LittleEndian>(byte_size).unwrap();
199 buf.write_i32::<LittleEndian>(point_count).unwrap();
200 }
201
202 #[tokio::test]
203 async fn test_parse_hierarchy_page() {
204 let mut page_data = Vec::new();
205 write_hierarchy_entry(&mut page_data, 0, 0, 0, 0, 1000, 256, 100);
206 write_hierarchy_entry(&mut page_data, 1, 0, 0, 0, 2000, 512, 50);
207 write_hierarchy_entry(&mut page_data, 1, 1, 0, 0, 5000, 128, -1);
208
209 let mut cache = HierarchyCache::new();
210 cache.parse_page(&page_data, 0).unwrap();
211
212 assert_eq!(cache.len(), 2); assert_eq!(cache.pending_pages.len(), 1); let root = cache
216 .get(&VoxelKey {
217 level: 0,
218 x: 0,
219 y: 0,
220 z: 0,
221 })
222 .unwrap();
223 assert_eq!(root.point_count, 100);
224 assert_eq!(root.offset, 1000);
225 }
226}