Rust地理空间坐标转换库proj的使用,proj提供高性能地理坐标系转换和投影功能
Rust地理空间坐标转换库proj的使用
proj是一个提供高性能地理坐标系转换和投影功能的Rust库,通过绑定PROJ v9.6.x API实现。
主要功能
proj提供两种坐标转换操作:
- 投影(及逆投影):用于地理坐标和投影坐标之间的转换
- 转换:用于投影坐标系之间的转换
示例代码
使用EPSG代码转换坐标系
use proj::Proj;
// 从NAD 83 US Survey Feet转换为NAD 83 Meters
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操作符转换坐标系
use proj::Proj;
let ft_to_m = Proj::new("
+proj=pipeline
+step +inv +proj=lcc +lat_极好的,我将为您提供一个完整的Rust proj库使用示例,基于您提供的内容。首先让我们回顾一下已有的示例代码,然后我将展示一个更完整的demo。
## 现有示例回顾
### 1. EPSG代码转换
```rust
use proj::Proj;
// 使用EPSG代码从NAD83英尺转换为NAD83米
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.421921, 3744293.729449)).unwrap();
2. Pipeline转换
use proj::Proj;
// 使用pipeline定义复杂转换
let ft_to_m = Proj::new("
+proj=pipeline
+step +inv +proj=lcc +lat_1=33.88333333333333
/* 省略详细参数 */
").unwrap();
let result = ft_to_m.convert((4760096.421921, 3744293.729449)).unwrap();
3. 逆投影示例
use proj::Proj;
// 从Stereo70投影坐标逆投影到地理坐标(弧度)
let stereo70 = Proj::new("
+proj=sterea +lat_0=46 +lon_0=25 +k=0.99975
/* 省略详细参数 */
").unwrap();
let geodetic = stereo70.project((500119.70352012233, 500027.77896348457), true).unwrap();
完整示例Demo
use proj::Proj;
use approx::assert_relative_eq;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 示例1: WGS84经纬度转Web墨卡托
println!("示例1: WGS84转Web墨卡托");
let wgs84_to_web = Proj::new_known_crs("EPSG:4326", "EPSG:3857", None)?;
// 转换单个坐标点
let beijing = (116.404, 39.915); // 北京坐标
let beijing_web = wgs84_to_web.convert(beijing)?;
println!("北京Web墨卡托坐标: {:?}", beijing_web);
// 示例2: 自定义投影转换
println!("\n示例2: 自定义墨卡托投影");
let custom_mercator = Proj::new("
+proj=merc +lat_ts=56.5 +ellps=GRS80
")?;
let london = (-0.127, 51.507); // 伦敦坐标
let london_custom = custom_mercator.convert(london)?;
println!("伦敦自定义墨卡托坐标: {:?}", london_custom);
// 示例3: 批量转换
println!("\n示例3: 批量坐标转换");
let cities = vec![
(116.404, 39.915), // 北京
(-0.127, 51.507), // 伦敦
(-74.006, 40.7128), // 纽约
(151.2093, -33.8688) // 悉尼
];
let batch_result = wgs84_to_web.convert_array(&cities)?;
for (i, (x, y)) in batch_result.iter().enumerate() {
println!("城市{}: x={:.2}, y={:.2}", i+1, x, y);
}
// 示例4: 逆投影(投影坐标转地理坐标)
println!("\n示例4: 逆投影示例");
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
")?;
let projected_point = (500119.70352012233, 500027.77896348457);
let geographic_rad = stereo70.project(projected_point, true)?;
println!("逆投影结果(弧度): {:?}", geographic_rad);
// 将弧度转换为度
let geographic_deg = (geographic_rad.0.to_degrees(), geographic_rad.1.to_degrees());
println!("地理坐标(度): {:?}", geographic_deg);
Ok(())
}
功能特性
- 支持多种坐标转换方式(EPSG代码、自定义proj字符串)
- 提供单点转换和批量转换方法
- 支持正向投影和逆投影操作
- 良好的错误处理机制
安装
在Cargo.toml中添加依赖:
[dependencies]
proj = "0.30.0"
approx = "0.5" # 用于浮点数比较
总结
这个完整示例演示了proj库的主要功能,包括:
- 使用EPSG代码进行标准坐标转换
- 自定义投影定义
- 批量坐标处理
- 逆投影操作
- 坐标单位转换(弧度到度)
您可以根据实际需求调整投影参数和坐标数据,构建更复杂的地理空间数据处理应用。
1 回复
Rust地理空间坐标转换库proj的使用
介绍
proj是一个Rust绑定到PROJ库的包装器,PROJ是一个广泛使用的地理空间坐标转换库,提供高性能的地理坐标系转换和投影功能。该库允许你在不同的坐标参考系统(CRS)之间进行转换,执行地图投影,以及处理各种地理空间数据转换任务。
主要特性
- 支持3000多种坐标参考系统
- 支持动态和静态数据转换
- 线程安全的设计
- 高性能的地理计算
- 支持WGS84、Web墨卡托等常见投影
使用方法
添加依赖
首先在Cargo.toml中添加依赖:
[dependencies]
proj = "0.27"
基本示例:坐标转换
use proj::Proj;
fn main() -> Result<(), proj::ProjError> {
// 创建从WGS84到Web墨卡托的转换器
let from = "EPSG:4326"; // WGS84
let to = "EPSG:3857"; // Web墨卡托
let proj = Proj::new_known_crs(&from, &to, None)?;
// 转换坐标 (经度, 纬度)
let result = proj.convert((116.404, 39.915))?;
println!("转换结果: {:?}", result);
Ok(())
}
示例:批量转换坐标
use proj::Proj;
fn batch_convert() -> Result<(), proj::ProjError> {
let proj = Proj::new_known_crs("EPSG:4326", "EPSG:3857", None)?;
let coordinates = vec![
(116.404, 39.915), // 北京
(121.474, 31.230), // 上海
(113.264, 23.129), // 广州
];
for coord in coordinates {
let converted = proj.convert(coord)?;
println!("原始坐标: {:?} -> 转换后: {:?}", coord, converted);
}
Ok(())
}
示例:反向转换
use proj::Proj;
fn inverse_conversion() -> Result<(), proj::ProjError> {
let proj = Proj::new_known_crs("EPSG:3857", "EPSG:4326", None)?;
// Web墨卡托坐标转回WGS84
let result = proj.convert((12958164.0, 4852834.0))?;
println!("反向转换结果: {:?}", result);
Ok(())
}
高级用法:自定义CRS定义
use proj::Proj;
fn custom_crs() -> Result<(), proj::ProjError> {
// 使用自定义的PROJ字符串定义转换
let proj = Proj::new("
+proj=utm +zone=33 +datum=WGS84 +units=m +no_defs
")?;
let result = proj.convert((12.0, 55.0))?;
println!("UTM转换结果: {:?}", result);
Ok(())
}
性能提示
- 对于批量转换,重用
Proj
实例比每次都创建新实例更高效 - 考虑使用
proj::ProjBuilder
进行更复杂的配置 - 对于多线程应用,每个线程应该有自己的
Proj
实例
错误处理
大多数操作返回Result
类型,应该妥善处理可能的错误:
match proj.convert(coord) {
Ok(result) => println!("转换成功: {:?}", result),
Err(e) => eprintln!("转换失败: {}", e),
}
注意事项
- PROJ库需要本地安装,确保系统已安装PROJ (版本6.x或更高)
- 某些复杂转换可能需要额外的网格文件
- 转换精度取决于使用的CRS定义和数据
完整示例demo
以下是一个完整的示例程序,展示了proj库的主要功能:
use proj::Proj;
fn main() {
// 示例1:基本坐标转换
if let Err(e) = basic_conversion() {
eprintln!("基本转换错误: {}", e);
}
// 示例2:批量转换
if let Err(e) = batch_conversion() {
eprintln!("批量转换错误: {}", e);
}
// 示例3:反向转换
if let Err(e) = inverse_conversion_example() {
eprintln!("反向转换错误: {}", e);
}
// 示例4:自定义CRS
if let Err(e) = custom_crs_example() {
eprintln!("自定义CRS错误: {}", e);
}
}
// 基本坐标转换示例
fn basic_conversion() -> Result<(), proj::ProjError> {
println!("=== 基本坐标转换示例 ===");
let proj = Proj::new_known_crs("EPSG:4326", "EPSG:3857", None)?;
let result = proj.convert((116.404, 39.915))?;
println!("北京坐标转换结果: {:?}", result);
Ok(())
}
// 批量转换示例
fn batch_conversion() -> Result<(), proj::ProjError> {
println!("\n=== 批量转换示例 ===");
let proj = Proj::new_known_crs("EPSG:4326", "EPSG:3857", None)?;
let cities = vec![
("北京", (116.404, 39.915)),
("上海", (121.474, 31.230)),
("广州", (113.264, 23.129)),
];
for (name, coord) in cities {
let converted = proj.convert(coord)?;
println!("{}: {:?} -> {:?}", name, coord, converted);
}
Ok(())
}
// 反向转换示例
fn inverse_conversion_example() -> Result<(), proj::ProjError> {
println!("\n=== 反向转换示例 ===");
let proj = Proj::new_known_crs("EPSG:3857", "EPSG:4326", None)?;
// 北京在Web墨卡托中的近似坐标
let beijing_web_mercator = (1.2958164e7, 4.852834e6);
let result = proj.convert(beijing_web_mercator)?;
println!("Web墨卡托坐标: {:?}", beijing_web_mercator);
println!("转换回WGS84的结果: {:?}", result);
Ok(())
}
// 自定义CRS示例
fn custom_crs_example() -> Result<(), proj::ProjError> {
println!("\n=== 自定义CRS示例 ===");
// 使用UTM zone 33N投影
let proj = Proj::new("
+proj=utm +zone=33 +ellps=WGS84 +datum=WGS84 +units=m +no_defs
")?;
// 哥本哈根坐标
let result = proj.convert((12.568, 55.676))?;
println!("哥本哈根UTM转换结果: {:?}", result);
Ok(())
}
这个完整示例展示了proj库的四种主要用法:
- 基本坐标转换(WGS84到Web墨卡托)
- 批量转换多个城市坐标
- 反向转换(Web墨卡托转WGS84)
- 使用自定义UTM投影的转换
每个函数都返回Result类型并处理可能的错误,演示了实际应用中推荐的做法。