terrio
Pure-Rust geospatial raster, vector and point cloud data I/O.
Documentation: https://terrio.opengeos.org
terrio aims to read, write, convert and reproject the geospatial formats most workflows use, without C dependencies, so that it builds anywhere Rust does, including WebAssembly.
Status: early development. Reading, writing and converting work; the processing operations are in progress. See ROADMAP.md.
terrio builds on the pure-Rust format libraries of
whitebox_next_gen (wbraster, wbvector,
wbprojection) and adds format detection, remote and archived inputs, a GeoTIFF reader built on
the tiff crate, fixes for what the format libraries miss, and
GDAL-style operations.
Coordinate transformations match GDAL's: terrio carries the EPSG CRSs with the coordinate
operations GDAL uses for them (generated from GDAL and PROJ by scripts/gen_epsg_table.py) and
pure-Rust ports of the projections they need. For each of the 6,354 EPSG geographic and projected
CRSs GDAL 3.12 transforms, transformations from and to WGS 84 agree with GDAL's within a
centimetre, and 99 % of a sample of transformations between two CRSs within a metre (see
crates/terrio/tests/epsg_accuracy.rs).
Command line
Install the terrio command, a standalone binary, with:
|
pip install terrio installs it too, and cargo install terrio-cli builds it from source (see
Installation).
# Point clouds: LAS 1.0-1.4 (formats 0-10, extra bytes, waveforms), LAZ, COPC and EPT (read in
# place, local or remote), PLY, E57; files larger than memory converted in chunks
Library
let ds = open?;
println!;
// Cloud Optimized GeoTIFFs are read in place: opening fetches the headers, and a window read
// fetches only the tiles it needs, with HTTP range requests.
let mut cog = open_raster_lazy?;
let options = WindowOptions ;
let window = cog.read_window?;
# Ok::
Remote reads are configured with environment variables: AWS_ACCESS_KEY_ID,
AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, AWS_PROFILE, AWS_REGION, AWS_NO_SIGN_REQUEST
and AWS_S3_ENDPOINT for S3; AZURE_STORAGE_ACCOUNT and AZURE_STORAGE_SAS_TOKEN for Azure;
TERRIO_HTTP_TIMEOUT, TERRIO_HTTP_MAX_RETRY and TERRIO_HTTP_LOG (and more, see the http
module) for HTTP.
Datasets can also be opened from bytes and written to bytes (terrio::memory), for data
already in memory and for WebAssembly, which has no file system.
An optional GDAL backend (the gdal cargo feature, off by default and the only C dependency)
opens what terrio has no driver for (HDF4, GRIB, NITF and the rest of GDAL's formats)
into the same data model, and writes rasters with GDAL's drivers: terrio::open("GDAL:file.hdf"),
terrio info --driver gdal, or a plain path when terrio's own drivers cannot open it.
Point clouds are read into columns, one typed vector per dimension (terrio::pointcloud):
use ;
// A COPC file is read in place: only the octree nodes in the bounds, down to level 4, are fetched.
let mut lidar = open_points?;
let filter = PointFilter ;
let ground = lidar.read?;
let z = ground.coords.unwrap;
write_points?;
let options = GridOptions ;
let dtm = grid?; // a RasterDataset
# Ok::
LAZ compression comes from the pure-Rust laz crate (the codec of
laspy's lazrs backend); terrio reads and writes the LAS container, extra bytes, CRS records and
COPC octrees itself.
Python
=
= # a NumPy array of the raster's own dtype
, , ,
= # read in place
=
= .
, ,
= # Arrow PyCapsule interface, GeoArrow geometries
= # pyarrow, GeoPandas, Polars, GDAL layers...
=
, , ,
The operations (convert, translate, warp, mosaic, rasterize, polygonize, dem,
calc, proximity, sieve) take the command-line options as keyword arguments. See
python/README.md.
rasterio scripts run with an import change, import terrio.rio as rasterio: datasets, windows,
CRSs, features, warping, merging, masking and memory files follow rasterio's API, compared with
rasterio on real files. See Coming from rasterio.
terrio.xarray is rioxarray's API without GDAL (pip install "terrio[xarray]"):
terrio.xarray.open_rasterio and xr.open_dataset(path, engine="terrio") open rasters lazily
(remote COGs fetch only the tiles a window needs, chunked with dask), and the .terrio accessor
has rioxarray's .rio methods (clip_box, clip, reproject, reproject_match, pad_box,
to_raster...), compared with rioxarray on real files. See
xarray.
JavaScript
The terrio-js npm package is the library compiled to WebAssembly, for browsers and Node.js:
import init from "terrio-js";
await ;
const dem = ;
dem.; // the summary `terrio info --json` prints
const band = dem.; // a Float32Array, Uint8Array...
const roads = ;
const fgb = roads.;
const ground = ; // LAS, LAZ, COPC
ground.; // a Float64Array
See js/README.md for the formats available in WebAssembly.
Testing against GDAL
scripts/fetch_test_data.sh downloads real-world files (Natural Earth, USGS 3DEP, Sentinel-2,
NASA ECOSTRESS and OPERA products, and more) and derives copies in other formats with GDAL.
scripts/conformance.py runs every comparison below and writes the conformance report
(docs/conformance.md, per format and operation: cases identical to GDAL, within tolerance or
different):
The comparisons, one by one:
TERRIO_TEST_DATA=../terrio-data
# convert with terrio, compare GDAL's reading
# queries, grids and reprojection vs PDAL
&& TERRIO_TEST_DATA=../../terrio-data TERRIO_TEST_DATA=../terrio-data TERRIO_TEST_DATA=../terrio-data
# every EPSG CRS's transformations against GDAL's
Layout
| Path | Contents |
|---|---|
crates/terrio |
The library |
crates/terrio-cli |
The terrio command-line tool |
python |
Python bindings (PyO3, NumPy), the terrio package on PyPI |
js |
WebAssembly bindings (wasm-bindgen), the terrio package on npm |
See ROADMAP.md for what is planned and in what order.
License
MIT
terrio's EPSG table (crates/terrio/data/epsg.tsv.zst) is derived from the
EPSG Geodetic Parameter Dataset, copyright the International Association of
Oil & Gas Producers (IOGP), whose terms of use permit its
redistribution with this attribution; the table was produced with PROJ and
GDAL. The projection formulas in crates/terrio/src/crs/ are ported from
PROJ (MIT licence).