#投影 #osgeo

proj

PROJ最新稳定版本的Rust高级绑定

55个版本

0.27.2 2023年7月7日
0.27.0 2022年6月23日
0.25.2 2022年2月20日
0.24.0 2021年10月20日
0.1.1 2015年7月1日

#22 in 地理空间

Download history 1008/week @ 2024-04-23 645/week @ 2024-04-30 711/week @ 2024-05-07 924/week @ 2024-05-14 1089/week @ 2024-05-21 910/week @ 2024-05-28 1065/week @ 2024-06-04 1067/week @ 2024-06-11 1129/week @ 2024-06-18 783/week @ 2024-06-25 893/week @ 2024-07-02 927/week @ 2024-07-09 947/week @ 2024-07-16 1068/week @ 2024-07-23 1388/week @ 2024-07-30 1182/week @ 2024-08-06

4,762 每月下载量
用于 10 个crate(8个直接使用)

MIT/Apache

5.5MB
5.5K SLoC

GitHub Workflow Status

PROJ

通过绑定到PROJ v9.2 API进行坐标变换。

目前提供了两种坐标变换操作:投影(及其逆投影)和转换

投影用于地球和投影坐标之间的变换以及相反(逆投影),而转换用于投影坐标系统之间的变换。PROJ 文档更详细地解释了这些操作之间的区别。

此crate依赖于libproj v9.2.x,通过proj-sys crate访问。默认情况下,proj-sys将尝试在您的系统上找到现有的libproj安装。如果找不到合适的libproj版本,构建脚本将尝试从源代码构建libproj。您可以使用bundled_proj特性指定从源代码构建。

开箱即用,任何(x, y)数字元组都可以作为输入提供给proj。您可以通过适配您自己的类型Coord特质来直接传递它们,以避免中间分配。默认启用了geo-types特性,该特性为geo-types crate中的类型实现了此特质。

还提供了对Coord的切片进行转换投影的方法。

示例

使用EPSG代码将NAD 83美国调查英尺转换为NAD 83米

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);

使用pipeline操作符将NAD 83美国调查英尺转换为NAD 83米

请注意,自v5.0.0版本起,PROJ使用pipeline运算符,它允许在转换中包含任意数量的步骤。以下示例的工作方式如下:

  • 将操作定义为pipeline操作
  • step 1定义为逆变换,产生大地坐标
  • step 2定义为正向变换到投影坐标,产生米。
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);

Stereo70到大地测量的逆向投影

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);

用法

创建转换有两种选项

  1. 如果您不需要额外的网格或其他自定义
    • 调用Proj::newProj::new_known_crs。这创建了一个转换实例(Proj
  2. 如果您需要执行转换的网格,或者您需要自定义搜索路径或网格端点

注意:

  1. ProjBuilderProj都实现了Info特质,可以用来获取关于当前PROJ实例状态的信息;
  2. Proj::new()ProjBuilder::proj()具有相同的签名;
  3. Proj::new_known_crs()ProjBuilder::proj_known_crs()具有相同的签名。

要求

默认情况下,该crate需要在您的系统上存在libproj 9.2.x。虽然它可能与较老的PROJ 6版本向后兼容,但这既没有被测试也没有得到支持。如果找不到合适的库,proj将尝试从源代码构建libproj

功能标志

  • geo-types:包含geo-types实现的特质。见示例
  • pkg_config:启用在链接到libproj时使用pkg-config —— 注意pkg-config必须在您的系统上可用。
  • bundled_proj:从proj-sys crate中打包的源代码构建libproj。注意,此功能需要在您的系统上存在Sqlite3和libtiff
  • network:公开了API,当启用时,可以从互联网获取网格数据以提高投影精度。有关详细信息,请参阅enable_network方法:enable_network

网络、缓存和搜索路径功能

网格文件下载

proj通过network功能支持网络网格下载功能。网络访问默认为禁用,可以通过传递true boolenable_network()来激活。可以使用network_enabled查询网络功能状态,并使用get_url_endpointset_url_endpoint查询和设置下载端点。

网格文件缓存

最多缓存300 MB下载的网格以节省带宽:可以通过grid_cache_enable启用或禁用此缓存。

搜索路径修改

可以使用set_search_paths修改用于搜索资源文件的路径。

符合您自己的类型

如果您有自己的几何类型,可以将它们符合到Coord特性和使用proj而不进行任何中间分配。

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);

geo-types集成

如果您已启用geo-types功能,可以跳过分配中间表示,并直接传递geo-types

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);

您还可以使用Transform特性和转换整个geo-types几何。

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, });

许可:MIT/Apache-2.0

依赖项

~1–15MB
~204K SLoC