• Stars
    star
    131
  • Rank 275,867 (Top 6 %)
  • Language
    Rust
  • License
    Apache License 2.0
  • Created over 9 years ago
  • Updated 7 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Rust bindings for the latest stable release of PROJ

GitHub Workflow Status

PROJ

Coordinate transformation via bindings to the PROJ v9.4 API.

Two coordinate transformation operations are currently provided: projection (and inverse projection) and conversion.

Projection is intended for transformations between geodetic and projected coordinates and vice versa (inverse projection), while conversion is intended for transformations between projected coordinate systems. The PROJ documentation explains the distinction between these operations in more detail.

This crate depends on libproj v9.4.x, accessed via the proj-sys crate. By default, proj-sys will try to find a pre-existing installation of libproj on your system. If an appropriate version of libproj cannot be found, the build script will attempt to build libproj from source. You may specify a from-source build with the bundled_proj feature.

Out of the box, any (x, y) numeric tuple can be provided as input to proj. You can conform your own types to the Coord trait to pass them in directly and avoid intermediate allocations. There is a geo-types feature, enabled by default, which implements this trait for types in the geo-types crate.

Methods for conversion and projection of slices of Coords are also available.

Examples

Convert from NAD 83 US Survey Feet to NAD 83 Meters Using EPSG Codes

use proj::Proj;

let from = "EPSG:2230";
let to = "EPSG:26946";
let ft_to_m = Proj::new_known_crs(&from, &to, None).unwrap();
let result = ft_to_m
    .convert((4760096.421921f64, 3744293.729449f64))
    .unwrap();
assert_relative_eq!(result.0, 1450880.2910605003);
assert_relative_eq!(result.1, 1141263.0111604529);

Convert from NAD 83 US Survey Feet to NAD 83 Meters Using the pipeline Operator

Note that as of v5.0.0, PROJ uses the pipeline operator, which allows an arbitrary number of steps in a conversion. The example below works as follows:

  • define the operation as a pipeline operation
  • define step 1 as an inverse transform, yielding geodetic coordinates
  • define step 2 as a forward transform to projected coordinates, yielding metres.
use proj::Proj;

let ft_to_m = Proj::new("
    +proj=pipeline
    +step +inv +proj=lcc +lat_1=33.88333333333333
    +lat_2=32.78333333333333 +lat_0=32.16666666666666
    +lon_0=-116.25 +x_0=2000000.0001016 +y_0=500000.0001016001 +ellps=GRS80
    +towgs84=0,0,0,0,0,0,0 +units=us-ft +no_defs
    +step +proj=lcc +lat_1=33.88333333333333 +lat_2=32.78333333333333 +lat_0=32.16666666666666
    +lon_0=-116.25 +x_0=2000000 +y_0=500000
    +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs
").unwrap();

// The Presidio, approximately
let result = ft_to_m.convert((4760096.421921f64, 3744293.729449f64)).unwrap();
assert_relative_eq!(result.0, 1450880.2910605003);
assert_relative_eq!(result.1, 1141263.01116045);

Inverse Projection from Stereo70 to Geodetic

use proj::Proj;

// Carry out an inverse projection from Pulkovo 1942(58) / Stereo70 (EPSG 3844)
// into geodetic lon and lat coordinates (in radians)
let stereo70 = Proj::new("
    +proj=sterea +lat_0=46 +lon_0=25 +k=0.99975 +x_0=500000 +y_0=500000
    +ellps=krass +towgs84=33.4,-146.6,-76.3,-0.359,-0.053,0.844,-0.84
    +units=m +no_defs
    ").unwrap();
let geodetic_radians_point = stereo70.project(
    (500119.70352012233f64, 500027.77896348457f64), true
).unwrap();
assert_relative_eq!(geodetic_radians_point.0, 0.436332, epsilon=1e-5);
assert_relative_eq!(geodetic_radians_point.1, 0.802851, epsiolon=1e-5);

Usage

There are two options for creating a transformation:

  1. If you don't require additional grids or other customisation:
    • Call Proj::new or Proj::new_known_crs. This creates a transformation instance (Proj)
  2. If you require a grid for the transformation you wish to carry out, or you need to customise the search path or the grid endpoint:

Note:

  1. Both ProjBuilder and Proj implement the Info trait, which can be used to get information about the current state of the PROJ instance;
  2. Proj::new() and ProjBuilder::proj() have the same signature;
  3. Proj::new_known_crs() and ProjBuilder::proj_known_crs() have the same signature.

Requirements

By default, the crate requires libproj 9.2.x to be present on your system. While it may be backwards-compatible with older PROJ 6 versions, this is neither tested nor supported. If a suitable library can't be found, proj will attempt to build libproj from source.

Feature Flags

  • geo-types: include trait impls for geo-types. See example.
  • pkg_config: enables the use of pkg-config when linking against libproj — note that pkg-config must be available on your system.
  • bundled_proj: builds libproj from source bundled in the proj-sys crate. Note that this feature requires Sqlite3 and libtiff to be present on your system.
  • network: exposes APIs which, when enabled, can fetch grid data from the internet to improve projection accuracy. See enable_network for details.

Network, Cache, and Search Path Functionality

Grid File Download

proj supports network grid download functionality via the network feature. Network access is disabled by default, and can be activated by passing a true bool to enable_network(). Network functionality status can be queried with network_enabled, and the download endpoint can be queried and set using get_url_endpoint and set_url_endpoint.

Grid File Cache

Up to 300 mb of downloaded grids are cached to save bandwidth: This cache can be enabled or disabled using grid_cache_enable.

Search Path Modification

The path used to search for resource files can be modified using set_search_paths

Conform your own types

If you have your own geometric types, you can conform them to the Coord trait and use proj without any intermediate allocation.

use proj::{Proj, Coord};

struct MyPointOfInterest {
    lat: f64,
    lon: f64,
}

impl Coord<f64> for MyPointOfInterest {
    fn x(&self) -> f64 {
        self.lon
    }
    fn y(&self) -> f64 {
        self.lat
    }
    fn from_xy(x: f64, y: f64) -> Self {
        Self { lon: x, lat: y }
    }
}

let donut_shop = MyPointOfInterest { lat: 34.095620, lon: -118.283555 };

let from = "EPSG:4326";
let to = "EPSG:3309";
let proj = Proj::new_known_crs(&from, &to, None).unwrap();

let result = proj.convert(donut_shop).unwrap();

assert_relative_eq!(result.x(), 158458.67251293268);
assert_relative_eq!(result.y(), -434296.8803996085);

Integration with geo-types

If you've enabled the geo-types feature, you can skip allocating an intermediate representation, and pass the geo-types directly.

use approx::assert_relative_eq;
use proj::Proj;
use geo_types::Point;

let my_point = Point::new(4760096.421921f64, 3744293.729449f64);

let from = "EPSG:2230";
let to = "EPSG:26946";
let nad_ft_to_m = Proj::new_known_crs(&from, &to, None).unwrap();

let result = nad_ft_to_m.convert(my_point).unwrap();

assert_relative_eq!(result.x(), 1450880.2910605003f64);
assert_relative_eq!(result.y(), 1141263.0111604529f64);

You can also transform entire geometries from geo-types by using the Transform trait.

use proj::{Proj, Transform};
use geo_types::{Coordinate, line_string};

let line = line_string![
    (x: -116.590457069172_f64, y: 32.55730630167689),
    (x: -116.590411068973, y: 32.55714830169309),
];
let proj = Proj::new_known_crs("EPSG:4326", "EPSG:6366", None).unwrap();

// create a new line with a different projection
let new_line = line.transformed(&proj).unwrap();

assert_eq!(new_line[0], Coordinate { x: 538447.8454476658, y: 3602285.563945497, });
assert_eq!(new_line[1], Coordinate { x: 538452.2313532799, y: 3602268.065714932, });

// or transform the original in-place
let mut line = line;
line.transform(&proj).unwrap();

assert_eq!(line[0], Coordinate { x: 538447.8454476658, y: 3602285.563945497, });
assert_eq!(line[1], Coordinate { x: 538452.2313532799, y: 3602268.065714932, });

License: MIT/Apache-2.0

More Repositories

1

geo

Geospatial primitives and algorithms for Rust
Rust
1,247
star
2

rstar

R*-tree spatial index for the Rust ecosystem
Rust
384
star
3

geozero

Zero-Copy reading and writing of geospatial data.
Rust
355
star
4

gdal

Rust bindings for GDAL
Rust
342
star
5

geojson

Library for serializing the GeoJSON vector GIS file format
Rust
222
star
6

geos

Rust bindings for GEOS
Rust
87
star
7

gpx

Rust read/write support for GPS Exchange Format (GPX)
Rust
84
star
8

geohash

Geohash for Rust
Rust
84
star
9

netcdf

High-level netCDF bindings for Rust
Rust
81
star
10

rinex

RINEX and GNSS data processing 🛰️
Rust
80
star
11

geotiff

Reading GeoTIFFs in Rust, nothing else!
Rust
69
star
12

geocoding

Geocoding library for Rust.
Rust
63
star
13

robust

Robust predicates for computational geometry
Rust
51
star
14

wkt

Rust read/write support for well-known text (WKT)
Rust
43
star
15

geographiclib-rs

A port of geographiclib in Rust.
Rust
41
star
16

kml

Rust support for KML
Rust
27
star
17

polyline

Google Encoded Polyline encoding & decoding in Rust.
Rust
17
star
18

osm

OSM XML serialization and other OpenStreetMap utilities
Rust
16
star
19

transitfeed

Public transit serializer/deserializer and manipulation library for Rust
Rust
16
star
20

ogcapi

OGC API building blocks implemented in Rust
Rust
14
star
21

topojson

TopoJSON bindings and utilities for Rust
Rust
10
star
22

world-file

Rust read/write support for world files
Rust
7
star
23

shapefile

Rust read/write support for shapefiles
HTML
7
star
24

tilejson

Library for serializing the TileJSON file format
Rust
6
star
25

geos-sys

FFI bindings for libgeos
C++
5
star
26

geo-svg

A rust library to generate SVGs for geo-types
Rust
5
star
27

georust.org

georust.org
3
star
28

meta

The GeoRust Team repository for coordinating and discussing GeoRust projects
Shell
1
star
29

docker-images

Docker images used in the GeoRust ecosystem
Makefile
1
star