Skip to main content

copc_temporal/
lib.rs

1//! Reader for the [COPC Temporal Index Extension](https://github.com/360-geo/copc/blob/master/copc-temporal/docs/temporal-index-spec.md).
2//!
3//! When a COPC file contains data from multiple survey passes over the same area,
4//! a spatial query alone returns points from *every* pass that touched that region.
5//! The temporal index extension adds per-node GPS time metadata so that clients can
6//! filter by time **before** decompressing any point data.
7//!
8//! This crate reads the temporal index incrementally via [`ByteSource`], matching
9//! the streaming design of [`copc_streaming`].
10//!
11//! # Quick start
12//!
13//! ```rust,ignore
14//! use copc_streaming::{CopcStreamingReader, FileSource};
15//! use copc_temporal::{GpsTime, TemporalCache};
16//!
17//! let mut reader = CopcStreamingReader::open(
18//!     FileSource::open("survey.copc.laz")?,
19//! ).await?;
20//! reader.load_all_hierarchy().await?;
21//!
22//! // Load the temporal index (returns None if the file has no temporal EVLR).
23//! // from_reader loads only the header and root page — not the entire index.
24//! let mut temporal = match TemporalCache::from_reader(&reader).await? {
25//!     Some(t) => t,
26//!     None => return Ok(()), // no temporal index in this file
27//! };
28//!
29//! // Define the time window we care about.
30//! let start = GpsTime(1_000_000.0);
31//! let end   = GpsTime(1_000_010.0);
32//!
33//! // Load only the temporal pages whose subtree overlaps our time range.
34//! // Pages covering other time periods are never fetched.
35//! temporal.load_pages_for_time_range(reader.source(), start, end).await?;
36//!
37//! // Find octree nodes that overlap the time window.
38//! let nodes = temporal.nodes_in_range(start, end);
39//!
40//! for entry in &nodes {
41//!     // Estimate the point sub-range within the node.
42//!     let hier = reader.get(&entry.key).unwrap();
43//!     let range = entry.estimate_point_range(
44//!         start, end, temporal.stride(), hier.point_count as u32,
45//!     );
46//!     println!("{:?}: points {}..{}", entry.key, range.start, range.end);
47//! }
48//! ```
49//!
50//! # Incremental page loading
51//!
52//! Like the spatial hierarchy, the temporal index is organised in pages.
53//! [`TemporalCache::from_reader`] loads the header and root page. You can then:
54//!
55//! - call [`TemporalCache::load_pages_for_time_range`] to fetch only the pages
56//!   whose subtree time bounds overlap your query — skipping irrelevant subtrees
57//!   entirely, or
58//! - call [`TemporalCache::load_all_pages`] to fetch everything at once.
59
60mod error;
61mod gps_time;
62mod temporal_cache;
63mod temporal_index;
64mod vlr;
65
66pub use error::TemporalError;
67pub use gps_time::GpsTime;
68pub use temporal_cache::{TemporalCache, TemporalHeader};
69pub use temporal_index::NodeTemporalEntry;
70
71// Re-export copc-streaming types that temporal consumers will need.
72pub use copc_streaming::{Aabb, ByteSource, VoxelKey};