Skip to main content

copc_streaming/
chunk.rs

1//! Point chunk fetching and LAZ decompression.
2
3use 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/// A decompressed point data chunk.
13pub struct DecompressedChunk {
14    pub key: VoxelKey,
15    /// Raw decompressed point record bytes.
16    pub data: Vec<u8>,
17    pub point_count: u32,
18    pub point_record_length: u16,
19}
20
21/// Fetch and decompress a single chunk.
22pub async fn fetch_and_decompress(
23    source: &impl ByteSource,
24    entry: &HierarchyEntry,
25    laz_vlr: &LazVlr,
26    point_record_length: u16,
27) -> Result<DecompressedChunk, CopcError> {
28    let compressed = source
29        .read_range(entry.offset, entry.byte_size as u64)
30        .await?;
31
32    let decompressed_size = entry.point_count as usize * point_record_length as usize;
33    let mut decompressed = vec![0u8; decompressed_size];
34
35    laz::decompress_buffer(&compressed, &mut decompressed, laz_vlr.clone())?;
36
37    Ok(DecompressedChunk {
38        key: entry.key,
39        data: decompressed,
40        point_count: entry.point_count as u32,
41        point_record_length,
42    })
43}
44
45/// Parse points from a decompressed chunk into `las::Point` values.
46pub fn read_points(
47    chunk: &DecompressedChunk,
48    header: &las::Header,
49) -> Result<Vec<las::Point>, CopcError> {
50    let format = header.point_format();
51    let transforms = header.transforms();
52    let mut cursor = Cursor::new(chunk.data.as_slice());
53    let mut points = Vec::with_capacity(chunk.point_count as usize);
54
55    for _ in 0..chunk.point_count {
56        let raw = las::raw::Point::read_from(&mut cursor, format)?;
57        points.push(las::Point::new(raw, transforms));
58    }
59
60    Ok(points)
61}