proj-core 0.10.0

Pure-Rust coordinate transformation library with no C dependencies
Documentation

proj-rust

proj-core crates.io proj-core docs.rs proj-wkt crates.io proj-wkt docs.rs

Pure-Rust coordinate transformation library. The default library surface has no C libraries, no build scripts, and no unsafe code.

Crates

  • proj-core: CRS definitions, operation selection, projection math, datum shifts, grid sampling, and transforms.
  • proj-epsg-format: the zero-dependency binary layout shared by the embedded EPSG registry reader and generator.
  • proj-wkt: parsing for EPSG codes, WKT, PROJ strings, PROJJSON, and a small Proj compatibility facade.

Usage

use proj_core::{Bounds, Transform};

let t = Transform::new("EPSG:4326", "EPSG:3857").unwrap();
let (x, y) = t.convert((-74.006, 40.7128)).unwrap();

let inv = t.inverse().unwrap();
let (lon, lat) = inv.convert((x, y)).unwrap();

let coords = vec![(-74.006, 40.7128); 1000];
let projected = t.convert_batch(&coords).unwrap();

let (x3, y3, z3) = t.convert_3d((-74.006, 40.7128, 15.0)).unwrap();

let bounds = Bounds::new(-74.3, 40.45, -73.65, 40.95);
let projected_bounds = t.transform_bounds(bounds, 8).unwrap();

Coordinates use CRS-native units:

  • Geographic CRS coordinates are longitude/latitude in degrees.
  • Projected CRS coordinates use the CRS linear unit, such as metres or US survey feet.
  • Without explicit vertical components, convert_3d() treats z as ellipsoidal height: projection-only paths preserve it, while horizontal datum shifts can change it. Explicit vertical components preserve, convert, or transform z according to their declared reference frames and units.

Strict transform constructors reject a compound-to-2D CRS pair because that would silently discard an explicit vertical reference. For an intentionally XY-only operation, use Transform::new_horizontal("EPSG:5845", "EPSG:4326"); the returned transform uses EPSG:5845's EPSG:3006 horizontal component.

With the default geo-types feature, Transform also supports geo_types::Coord<f64> and full 2D geometry conversion through convert_geometry().

CRS Input

proj-core accepts registry-backed EPSG codes such as "EPSG:4326" and "EPSG:3857".

proj-wkt accepts:

  • EPSG authority codes, bare EPSG numbers, EPSG URNs, and OGC CRS:84.
  • Common PROJ strings for the implemented projection families, including legacy +init=epsg:XXXX.
  • WKT1 and supported WKT2 geographic/projected CRS definitions.
  • WKT1 COMPD_CS and WKT2 COMPOUNDCRS definitions with explicit vertical components.
  • Basic PROJJSON geographic, projected, and compound CRS definitions.

Custom definitions are accepted only when they map to this library's CRS model: longitude/east, latitude/north geographic axes in degrees with a Greenwich prime meridian, and projected easting/northing axes in a single linear unit. EPSG-tagged WKT1 definitions may use the authority-native axis order; a pure axis permutation is canonicalized to the library's coordinate order after the embedded definition is validated against the registry. Unsupported custom axis order, axis directions, prime meridian, angular unit, projection, or vertical transformation semantics return errors.

Supported CRS

CRS or projection EPSG examples
Geographic CRS and datum identity EPSG:4326, EPSG:4269, EPSG:4267, EPSG:4258
3D geographic and compatible compound CRS EPSG:4979
Generated vertical CRS metadata and same-reference unit conversion EPSG:3855, EPSG:5702, EPSG:5703, EPSG:5773, EPSG:6360, EPSG:5709, and other supported EPSG vertical CRS records
Grid-based 3D compound (with geotiff) EPSG:7415 (RD New + NAP, RDNAPTRANS2018)
Web Mercator EPSG:3857
Transverse Mercator / UTM EPSG:32601-32660, EPSG:32701-32760
Polar Stereographic EPSG:3413, EPSG:3031, EPSG:3995, EPSG:32661, EPSG:32761
Lambert Conformal Conic, including 1SP, Michigan, and 1SP variant B EPSG:2154, EPSG:3347, EPSG:24200, EPSG:6201, EPSG:9549
Albers Equal Area EPSG:5070, EPSG:3005
Lambert Azimuthal Equal Area EPSG:3035, EPSG:3408, EPSG:6931, EPSG:9311
Oblique Stereographic EPSG:28992, EPSG:2953
Hotine Oblique Mercator / RSO EPSG:2056, EPSG:3078, EPSG:3375
Cassini-Soldner EPSG:30200, EPSG:3377
Mercator EPSG:3395
Equidistant Cylindrical EPSG:32662
Colombia Urban EPSG:6247
Krovak north-orientated and modified north-orientated EPSG:5514, EPSG:5516, EPSG:8353
Equal Earth EPSG:8857, EPSG:8858, EPSG:8859
American Polyconic EPSG:5880, EPSG:29101
Azimuthal Equidistant, Modified Azimuthal Equidistant, and Guam Projection EPSG:27701, EPSG:3295, EPSG:3993

Transform::new() and Transform::from_crs_defs() select the best supported operation for a CRS pair. Use Transform::with_selection_options() or Transform::from_crs_defs_with_selection_options() to set an area of interest, require grid-backed operations, require exact area matches, provide a GridProvider, select an explicit registry operation, or provide explicit custom horizontal CoordinateOperation candidates.

Operation selection candidates come only from the embedded registry, deterministic generated-registry records, explicit caller/parser-provided coordinate operations, and internal identity/no-datum-operation behavior. Selection does not synthesize Helmert, grid, or WGS84-compatible identity operations from datum metadata. CRS pairs without a registry/generated-registry operation, explicit operation, or identity path fail during transform construction.

Grids

Horizontal NTv2 grid shifts are supported through embedded registry operations, parsed PROJ +nadgrids definitions built with proj-wkt transform helpers or the Proj facade, EmbeddedGridProvider, FilesystemGridProvider, and custom GridProvider implementations.

Vertical GTX geoid operations are supported for registry-backed ellipsoidal-to-gravity height pairs and explicit VerticalGridOperation values. Grid files are resolved through a caller-provided FilesystemGridProvider or custom GridProvider; geoid grid files are not bundled.

With the geotiff feature, PROJ-format GeoTIFF/COG grids (.tif, as distributed on the PROJ CDN) are decoded for both horizontal (NTv2-equivalent latitude/longitude offsets, including nested subgrids) and vertical (geoid undulation) shifts. This enables grid-based transforms such as RDNAPTRANS™2018 — ETRS89/WGS 84 3D (EPSG:4979) to RD New + NAP height (EPSG:7415) — matching PROJ to sub-millimetre. Supply the nl_nsgi_rdtrans2018.tif and nl_nsgi_nlgeo2018.tif grids through a FilesystemGridProvider:

use std::sync::Arc;
use proj_core::{FilesystemGridProvider, SelectionOptions, Transform};

let provider = Arc::new(FilesystemGridProvider::new(vec!["/path/to/grids".into()]));
let options = SelectionOptions::new().with_grid_provider(provider);
let t = Transform::with_selection_options("EPSG:4979", "EPSG:7415", options).unwrap();
let (rd_x, rd_y, nap) = t.convert_3d((6.605585, 53.294378, 50.0)).unwrap();

Grid diagnostics expose selected operation metadata and resolved grid SHA-256 checksums.

Feature Flags

Flag Default Description
rayon yes Parallel batch transforms via convert_batch_parallel()
geo-types yes geo_types::Coord<f64> conversions and geometry transforms
geotiff no Decode PROJ-format GeoTIFF/COG datum-shift and geoid grids (e.g. RDNAPTRANS2018) via the pure-Rust geotiff-reader crate
serde no Serialize/Deserialize for coordinate and operation-metadata value types
c-proj-compat no Reference-compatibility tests against bundled C PROJ

Development

cargo test --workspace
cargo test -p proj-core --no-default-features
cargo clippy --workspace --all-targets -- -D warnings

The optional c-proj-compat feature and gen-reference tool intentionally use bundled C PROJ/sqlite for reference comparisons and registry generation; they are not part of the default library surface.

The embedded EPSG registry is generated from the bundled PROJ proj.db:

cargo run --manifest-path gen-reference/Cargo.toml --bin gen-registry
./scripts/check-registry-generation.sh

During generation, supported PROJ grid alternatives can be composed with known zero/identity bridge operations to create deterministic generated coordinate operations when EPSG source or target CRS definitions need bridging.

Reference comparisons and benchmark results are in docs/benchmark-report.md.

License

MIT OR Apache-2.0