Skip to main content

copc_streaming/
lib.rs

1//! Async streaming reader for [COPC](https://copc.io/) (Cloud-Optimized Point Cloud) files.
2//!
3//! COPC organises LAS/LAZ point cloud data in a spatial octree so that clients can
4//! fetch only the regions they need. This crate reads COPC files incrementally through
5//! the [`ByteSource`] trait — any random-access backend (local files, HTTP range
6//! requests, in-memory buffers) works out of the box.
7//!
8//! # Quick start
9//!
10//! ```rust,ignore
11//! use copc_streaming::{Aabb, CopcStreamingReader, FileSource};
12//!
13//! let mut reader = CopcStreamingReader::open(
14//!     FileSource::open("points.copc.laz")?,
15//! ).await?;
16//!
17//! let root_bounds = reader.copc_info().root_bounds();
18//!
19//! // Load only the hierarchy pages that cover the region you care about.
20//! reader.load_hierarchy_for_bounds(&my_query_box).await?;
21//!
22//! // Walk loaded nodes — only those intersecting the query box.
23//! for (key, entry) in reader.entries() {
24//!     if entry.point_count == 0 { continue; }
25//!     if !key.bounds(&root_bounds).intersects(&my_query_box) { continue; }
26//!
27//!     let chunk = reader.fetch_chunk(key).await?;
28//!     let points = reader.read_points(&chunk)?;
29//!     // each `point` has .x, .y, .z, .gps_time, .color, etc.
30//! }
31//! ```
32//!
33//! # Load everything at once
34//!
35//! If you don't need spatial filtering, pull the full hierarchy in one call:
36//!
37//! ```rust,ignore
38//! let mut reader = CopcStreamingReader::open(
39//!     FileSource::open("points.copc.laz")?,
40//! ).await?;
41//! reader.load_all_hierarchy().await?;
42//!
43//! // Every node is now available via reader.entries() / reader.get().
44//! ```
45//!
46//! # Hierarchy loading
47//!
48//! The COPC hierarchy is stored as a tree of *pages*. Each page contains metadata
49//! for a group of octree nodes (typically several levels deep) plus pointers to
50//! child pages covering deeper subtrees.
51//!
52//! [`CopcStreamingReader::open`] reads the LAS header, COPC info, and the **root
53//! hierarchy page**. This gives you the coarse octree nodes immediately (often
54//! levels 0–3, depending on the file). Any subtrees stored in separate pages
55//! are tracked as *pending pages* — they haven't been fetched yet.
56//!
57//! You then control when and which deeper pages are loaded:
58//!
59//! - [`load_hierarchy_for_bounds`](CopcStreamingReader::load_hierarchy_for_bounds) —
60//!   load only pages whose subtree intersects a bounding box. Call this when the
61//!   camera moves or a spatial query arrives.
62//! - [`load_pending_pages`](CopcStreamingReader::load_pending_pages) — fetch the
63//!   next batch of pending pages (all of them). Useful when you don't need spatial
64//!   filtering and just want to go one level deeper.
65//! - [`load_all_hierarchy`](CopcStreamingReader::load_all_hierarchy) — convenience
66//!   to pull every remaining page in one go.
67//! - [`children`](CopcStreamingReader::children) — list loaded children of a node.
68//!   Returns only children already in the cache; if deeper pages haven't been
69//!   loaded yet this may return fewer than exist in the file.
70//! - [`has_pending_pages`](CopcStreamingReader::has_pending_pages) — check if there
71//!   are still unloaded pages.
72//!
73//! # Custom byte sources
74//!
75//! Implement [`ByteSource`] to read from any backend. The trait requires only
76//! `read_range(offset, length)` and `size()`. A default `read_ranges` implementation
77//! issues sequential reads — override it for backends that support parallel fetches
78//! (e.g. HTTP/2 multiplexing).
79//!
80//! Built-in implementations: [`FileSource`] (local files), `Vec<u8>` and `&[u8]`
81//! (in-memory).
82//!
83//! Futures returned by `ByteSource` are *not* required to be `Send`, so the crate
84//! works in single-threaded runtimes and WASM environments.
85
86mod byte_source;
87mod chunk;
88mod error;
89mod file_source;
90mod header;
91mod hierarchy;
92mod reader;
93mod types;
94
95pub use byte_source::ByteSource;
96pub use chunk::DecompressedChunk;
97pub use error::CopcError;
98pub use file_source::FileSource;
99pub use header::{CopcHeader, CopcInfo};
100pub use hierarchy::{HierarchyCache, HierarchyEntry};
101pub use reader::CopcStreamingReader;
102pub use types::{Aabb, VoxelKey};