#[non_exhaustive]pub struct Chunk {
pub key: VoxelKey,
pub fields: Fields,
/* private fields */
}Expand description
A decompressed point data chunk.
A Chunk wraps a las::PointData along with the VoxelKey of the
octree node it came from and the Fields mask that was used to decode
it. Column accessors (intensity, gps_time, rgb, …) are guarded by
the mask and return None for fields that were not decoded.
Construct via CopcStreamingReader::fetch_chunk
or CopcStreamingReader::query_chunks.
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.key: VoxelKeyThe octree node this chunk belongs to.
fields: FieldsWhich fields were actually decompressed into this chunk.
Implementations§
Source§impl Chunk
impl Chunk
Sourcepub fn new(key: VoxelKey, fields: Fields, cloud: PointData) -> Self
pub fn new(key: VoxelKey, fields: Fields, cloud: PointData) -> Self
Construct a Chunk from a VoxelKey, a Fields mask, and a
las::PointData.
Normally you’ll get chunks from
CopcStreamingReader::fetch_chunk;
this constructor exists for callers that drive their own
decompression pipeline (and for tests). The caller is responsible
for ensuring that fields accurately describes which LAZ layers
were decoded into cloud — otherwise the chunk’s field guards will
hide columns that are actually valid, or (worse) expose columns
that contain zero’d bytes for skipped layers.
Sourcepub fn cloud(&self) -> &PointData
pub fn cloud(&self) -> &PointData
Borrow the underlying las::PointData — an unchecked escape
hatch to the raw byte-level accessors in las.
Use this when Chunk’s higher-level methods don’t expose what
you need: cloud.x_raw(), cloud.record_len(), cloud.raw_bytes(),
cloud.iter() for zero-copy PointRef walks, etc.
§⚠ Field guards are bypassed
Calling cloud.rgb(), cloud.gps_time(), cloud.intensity(), or
any PointRef accessor on bytes from this cloud does not check
whether the underlying layer was actually decoded. If you call one
of those on a chunk that was fetched without the corresponding
Fields flag, you get a valid-looking iterator of zeros.
Prefer the Chunk methods (rgb,
gps_time, etc.) — they return None when the
field is absent, making the hazard impossible to hit accidentally.
Sourcepub fn point_count(&self) -> usize
pub fn point_count(&self) -> usize
Number of points in this chunk.
Sourcepub fn to_points(&self) -> Result<Vec<Point>, CopcError>
pub fn to_points(&self) -> Result<Vec<Point>, CopcError>
Materialize every point in this chunk as an owned las::Point.
Returns CopcError::PartialDecode if this chunk was decoded with a
partial field mask — otherwise the resulting las::Points would have
silently-zero values for skipped fields.
This is the bridge from the column-oriented Chunk API back to
the simple Vec<las::Point> API. Prefer the column accessors
(intensity, gps_time, …)
or chunk.cloud().iter() when you don’t need owned values.
Sourcepub fn points_at(&self, indices: &[u32]) -> Result<Vec<Point>, CopcError>
pub fn points_at(&self, indices: &[u32]) -> Result<Vec<Point>, CopcError>
Materialize las::Point values only at the given indices.
Pair with indices_in_bounds or any
other index-producing filter to skip the materialization cost for
rejected points entirely:
let chunk = reader.fetch_chunk(&key, Fields::ALL).await?;
let indices = chunk.indices_in_bounds(&bounds).unwrap();
let points = chunk.points_at(&indices)?;Returns CopcError::PartialDecode if the chunk was decoded with
a partial field mask, same as to_points.
Sourcepub fn positions(&self) -> Option<impl Iterator<Item = [f64; 3]> + '_>
pub fn positions(&self) -> Option<impl Iterator<Item = [f64; 3]> + '_>
Iterate (x, y, z) world coordinates as [f64; 3], or None if
Fields::Z was not set.
x and y are always decoded on LAS 1.4 layered formats (they
share the always-on base layer with return_number,
number_of_returns and scanner_channel), but z is its own
skippable layer. A chunk without Fields::Z has zero bytes in the
z slots; returning None here keeps the footgun out of reach.
Sourcepub fn intensity(&self) -> Option<impl Iterator<Item = u16> + '_>
pub fn intensity(&self) -> Option<impl Iterator<Item = u16> + '_>
Intensity column, or None if Fields::INTENSITY was not set
or the format does not include intensity.
Sourcepub fn classification(&self) -> Option<impl Iterator<Item = u8> + '_>
pub fn classification(&self) -> Option<impl Iterator<Item = u8> + '_>
Classification byte column, or None if Fields::CLASSIFICATION
was not set.
Sourcepub fn scan_angle(&self) -> Option<impl Iterator<Item = f32> + '_>
pub fn scan_angle(&self) -> Option<impl Iterator<Item = f32> + '_>
Scan angle column in degrees, or None if Fields::SCAN_ANGLE
was not set.
Sourcepub fn user_data(&self) -> Option<impl Iterator<Item = u8> + '_>
pub fn user_data(&self) -> Option<impl Iterator<Item = u8> + '_>
User data byte column, or None if Fields::USER_DATA was not set.
Sourcepub fn point_source_id(&self) -> Option<impl Iterator<Item = u16> + '_>
pub fn point_source_id(&self) -> Option<impl Iterator<Item = u16> + '_>
Point source ID column, or None if Fields::POINT_SOURCE_ID
was not set.
Sourcepub fn gps_time(&self) -> Option<impl Iterator<Item = f64> + '_>
pub fn gps_time(&self) -> Option<impl Iterator<Item = f64> + '_>
GPS time column, or None if Fields::GPS_TIME was not set or
the format does not include GPS time.
Sourcepub fn rgb(&self) -> Option<impl Iterator<Item = (u16, u16, u16)> + '_>
pub fn rgb(&self) -> Option<impl Iterator<Item = (u16, u16, u16)> + '_>
RGB column, or None if Fields::RGB was not set or the format
does not include color.
Sourcepub fn nir(&self) -> Option<impl Iterator<Item = u16> + '_>
pub fn nir(&self) -> Option<impl Iterator<Item = u16> + '_>
NIR column, or None if Fields::NIR was not set or the format
does not include NIR.
Sourcepub fn indices_in_bounds(&self, bounds: &Aabb) -> Option<Vec<u32>>
pub fn indices_in_bounds(&self, bounds: &Aabb) -> Option<Vec<u32>>
Indices of points inside bounds, or None if Fields::Z was
not set.
A 3D bounding-box intersection requires z, so a chunk without
Fields::Z can’t produce meaningful results — None makes that
impossible to misuse. Pair the returned indices with any column
iterator on the chunk to produce a filtered view without
materializing las::Point values.
Sourcepub fn decompress(
compressed: &[u8],
entry: &HierarchyEntry,
laz_vlr: &LazVlr,
header: &Header,
fields: Fields,
) -> Result<Self, CopcError>
pub fn decompress( compressed: &[u8], entry: &HierarchyEntry, laz_vlr: &LazVlr, header: &Header, fields: Fields, ) -> Result<Self, CopcError>
Decompress already-fetched compressed bytes into a Chunk.
Public counterpart to the sync inner that
CopcStreamingReader::fetch_chunks
uses internally. Useful when the caller wants to issue the
ByteSource::read_range on one
executor (e.g. the browser main thread) and run the CPU-bound
LAZ decompression on another (e.g. a Rayon worker pool).
compressed must be exactly entry.byte_size bytes for the
chunk referenced by entry.key. laz_vlr and header come
from CopcStreamingReader::header
and are immutable for the lifetime of the dataset, so a caller
can clone them out of the reader once and reuse them.
§Example
// Fetch on one thread, hand bytes to a worker for decode:
let entry = reader.get(&key).unwrap().clone();
let bytes = reader
.source()
.read_range(entry.offset, entry.byte_size as u64)
.await?;
// ... move bytes to a worker thread ...
let chunk = Chunk::decompress(
&bytes,
&entry,
reader.header().laz_vlr(),
reader.header().las_header(),
Fields::Z | Fields::RGB,
)?;