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库的主要功能,包括:

  1. 使用EPSG代码进行标准坐标转换
  2. 自定义投影定义
  3. 批量坐标处理
  4. 逆投影操作
  5. 坐标单位转换(弧度到度)

您可以根据实际需求调整投影参数和坐标数据,构建更复杂的地理空间数据处理应用。


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(())
}

性能提示

  1. 对于批量转换,重用Proj实例比每次都创建新实例更高效
  2. 考虑使用proj::ProjBuilder进行更复杂的配置
  3. 对于多线程应用,每个线程应该有自己的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库的四种主要用法:

  1. 基本坐标转换(WGS84到Web墨卡托)
  2. 批量转换多个城市坐标
  3. 反向转换(Web墨卡托转WGS84)
  4. 使用自定义UTM投影的转换

每个函数都返回Result类型并处理可能的错误,演示了实际应用中推荐的做法。

回到顶部