Pure-Rust coordinate transformation library. The default library surface has no C libraries, no build scripts, and no unsafe code.
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 smallProjcompatibility facade.
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()treatszas ellipsoidal height: projection-only paths preserve it, while horizontal datum shifts can change it. Explicit vertical components preserve, convert, or transformzaccording 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().
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_CSand WKT2COMPOUNDCRSdefinitions 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.
| 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.
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.
| 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 |
cargo test --workspace
cargo test -p proj-core --no-default-features
cargo clippy --workspace --all-targets -- -D warningsThe 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.shDuring 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.
MIT OR Apache-2.0