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