1use std::io::Cursor;
4
5use laz::LazVlr;
6
7use crate::byte_source::ByteSource;
8use crate::error::CopcError;
9use crate::hierarchy::HierarchyEntry;
10use crate::types::VoxelKey;
11
12#[non_exhaustive]
14pub struct DecompressedChunk {
15 pub key: VoxelKey,
17 pub data: Vec<u8>,
19 pub point_count: u32,
21 pub point_record_length: u16,
23}
24
25pub async fn fetch_and_decompress(
27 source: &impl ByteSource,
28 entry: &HierarchyEntry,
29 laz_vlr: &LazVlr,
30 point_record_length: u16,
31) -> Result<DecompressedChunk, CopcError> {
32 let compressed = source
33 .read_range(entry.offset, entry.byte_size as u64)
34 .await?;
35
36 let decompressed_size = entry.point_count as usize * point_record_length as usize;
37 let mut decompressed = vec![0u8; decompressed_size];
38
39 laz::decompress_buffer(&compressed, &mut decompressed, laz_vlr.clone())?;
40
41 Ok(DecompressedChunk {
42 key: entry.key,
43 data: decompressed,
44 point_count: entry.point_count,
45 point_record_length,
46 })
47}
48
49pub fn read_points(
51 chunk: &DecompressedChunk,
52 header: &las::Header,
53) -> Result<Vec<las::Point>, CopcError> {
54 read_points_range(chunk, header, 0..chunk.point_count)
55}
56
57pub fn read_points_range(
62 chunk: &DecompressedChunk,
63 header: &las::Header,
64 range: std::ops::Range<u32>,
65) -> Result<Vec<las::Point>, CopcError> {
66 if range.end > chunk.point_count {
67 return Err(CopcError::Io(std::io::Error::new(
68 std::io::ErrorKind::InvalidInput,
69 format!(
70 "point range {}..{} exceeds chunk point count {}",
71 range.start, range.end, chunk.point_count
72 ),
73 )));
74 }
75
76 let format = header.point_format();
77 let transforms = header.transforms();
78 let record_len = chunk.point_record_length as u64;
79
80 let start = (range.start as u64 * record_len) as usize;
81 let count = range.end.saturating_sub(range.start) as usize;
82
83 let mut cursor = Cursor::new(&chunk.data[start..]);
84 let mut points = Vec::with_capacity(count);
85
86 for _ in 0..count {
87 let raw = las::raw::Point::read_from(&mut cursor, format)?;
88 points.push(las::Point::new(raw, transforms));
89 }
90
91 Ok(points)
92}