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