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