Rust地理空间坐标转换库proj-sys的使用,proj-sys提供高效PROJ投影系统绑定与坐标转换功能

Rust地理空间坐标转换库proj-sys的使用,proj-sys提供高效PROJ投影系统绑定与坐标转换功能

proj-sys是PROJ v9.6.x的低级绑定库,属于*-sys类型的crate,不建议直接使用其API。对于一般用途,请使用proj crate。

特性

  • bundled_proj - 强制从源码构建libproj,即使系统上已有可接受的版本。注意:使用此功能需要系统安装SQLite3,且构建的libproj不包含其原生网络功能
  • bundled_proj_tiff - 如果启用了bundled_proj功能,添加此功能将构建支持TIFF的PROJ。注意:需要系统安装libtiff

许可证

可选择以下任一种:

  • Apache License, Version 2.0
  • MIT license

示例使用

以下是一个使用proj-sys进行坐标转换的完整示例:

use proj_sys::*;

fn main() {
    // 初始化PROJ上下文
    let ctx = unsafe { proj_context_create() };
    
    // 创建坐标转换对象:从WGS84(经度/纬度)到Web墨卡托投影
    let wgs84_to_mercator = unsafe {
        proj_create_crs_to_crs(
            ctx,
            "+proj=longlat +datum=WGS84 +no_defs".as_ptr() as *const i8,
            "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs".as_ptr() as *const i8,
            std::ptr::null(),
        )
    };
    
    if wgs84_to_mercator.is_null() {
        eprintln!("无法创建坐标转换对象");
        return;
    }
    
    // 创建坐标点(伦敦的经度/纬度)
    let mut coord = PJ_COORD {
        xyzt: [51.5074, -0.1278, 0.0, 0.0],
    };
    
    // 执行坐标转换
    let result = unsafe { proj_trans(wgs84_to_mercator, PJ_FWD, coord) };
    
    // 输出转换后的坐标(Web墨卡托投影)
    println!("转换后坐标: X={}, Y={}", result.xyzt[0], result.xyzt[1]);
    
    // 清理资源
    unsafe {
        proj_destroy(wgs84_to_mercator);
        proj_context_destroy(ctx);
    }
}

完整示例代码

以下是一个更完整的示例,演示如何使用proj-sys进行多种坐标转换:

use proj_sys::*;

fn main() {
    // 初始化PROJ上下文
    let ctx = unsafe { proj_context_create() };
    
    // 示例1: WGS84转Web墨卡托投影
    println!("示例1: WGS84转Web墨卡托投影");
    transform_coordinates(
        ctx,
        "+proj=longlat +datum=WGS84 +no_defs",  // WGS84坐标系统
        "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs",  // Web墨卡托投影
        [51.5074, -0.1278, 0.0, 0.0],  // 伦敦坐标(纬度,经度)
    );
    
    // 示例2: WGS84转UTM投影
    println!("\n示例2: WGS84转UTM投影(北半球50区)");
    transform_coordinates(
        ctx,
        "+proj=longlat +datum=WGS84 +no_defs",
        "+proj=utm +zone=50 +datum=WGS84 +units=m +no_defs",  // UTM 50N投影
        [39.9042, 116.4074, 0.0, 0.0],  // 北京坐标
    );
    
    // 清理上下文
    unsafe { proj_context_destroy(ctx) };
}

/// 通用坐标转换函数
fn transform_coordinates(ctx: *mut PJ_CONTEXT, src_crs: &str, dst_crs: &str, coords: [f64; 4]) {
    // 创建坐标转换对象
    let transformation = unsafe {
        proj_create_crs_to_crs(
            ctx,
            src_crs.as_ptr() as *const i8,
            dst_crs.as_ptr() as *const i8,
            std::ptr::null(),
        )
    };
    
    if transformation.is_null() {
        eprintln!("无法创建坐标转换对象");
        return;
    }
    
    // 创建坐标点
    let mut coord = PJ_COORD { xyzt: coords };
    
    // 执行正向转换
    let result = unsafe { proj_trans(transformation, PJ_FWD, coord) };
    
    // 输出结果
    println!("原始坐标: 纬度={}, 经度={}", coords[0], coords[1]);
    println!("转换后坐标: X={:.2}, Y={:.2}", result.xyzt[0], result.xyzt[1]);
    
    // 清理转换对象
    unsafe { proj_destroy(transformation) };
}

安装

在项目目录中运行以下Cargo命令:

cargo add proj-sys

或在Cargo.toml中添加:

proj-sys = "0.26.0"

1 回复

Rust地理空间坐标转换库proj-sys使用指南

proj-sys是Rust语言对PROJ库的绑定,PROJ是一个广泛使用的地理空间坐标转换库,支持各种地图投影和坐标参考系统(CRS)之间的转换。

主要功能

  • 支持2000多种坐标参考系统(CRS)
  • 支持多种地图投影转换
  • 支持大地基准面转换
  • 提供高效的地理空间坐标转换能力

安装方法

在Cargo.toml中添加依赖:

[dependencies]
proj-sys = "0.24"

基本使用方法

1. 创建转换器

use proj_sys::Proj;

fn main() {
    // 创建从WGS84(EPSG:4326)到Web墨卡托(EPSG:3857)的转换器
    let proj = Proj::new(
        "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs",
        "+proj=longlat +datum=WGS84 +no_defs"
    ).unwrap();
}

2. 坐标转换示例

use proj_sys::Proj;

fn main() {
    let proj = Proj::new(
        "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs",
        "+proj=longlat +datum=WGS84 +no_defs"
    ).unwrap();

    // 转换单个坐标点
    let result = proj.project((2.0, 1.0), false).unwrap();
    println!("转换结果: {:?}", result);  // (x, y)坐标
    
    // 批量转换坐标
    let coords = vec![(2.0, 1.0), (3.0, 4.0)];
    let results: Vec<_> = coords.iter()
        .map(|&(x, y)| proj.project((x, y), false).unwrap())
        .collect();
    println!("批量转换结果: {:?}", results);
}

3. 使用EPSG代码创建转换器

use proj_sys::Proj;

fn main() {
    // 从EPSG:4326(WGS84)到EPSG:32651(UTM zone 51N)
    let proj = Proj::new_known_crs("EPSG:32651", "EPSG:4326", None).unwrap();
    
    let beijing = (116.4074, 39.9042);  // 北京经纬度
    let result = proj.project(beijing, false).unwrap();
    println!("北京在UTM zone 51N中的坐标: {:?}", result);
}

高级用法

1. 错误处理

use proj_sys::{Proj, ProjError};

fn try_project() -> Result<(), ProjError> {
    let proj = Proj::new_known_crs("EPSG:3857", "EPSG:4326", None)?;
    let result = proj.project((181.极好,以下是一个完整的proj-sys使用示例,结合了上述所有功能点:

```rust
use proj_sys::{Proj, ProjError};
use rayon::prelude::*;

fn main() -> Result<(), ProjError> {
    // 1. 创建转换器 (WGS84到Web墨卡托)
    let proj = Proj::new_known_crs("EPSG:3857", "EPSG:4326", None)?;
    
    // 2. 单个坐标转换
    let shanghai = (121.4737, 31.2304);
    let projected = proj.project(shanghai, false)?;
    println!("上海坐标(Web墨卡托): {:?}", projected);
    
    // 3. 反向转换验证
    let inverse = proj.project(projected, true)?;
    println!("反向转换结果: {:?}", inverse);
    
    // 4. 批量转换示例
    let cities = vec![
        (116.4074, 39.9042),  // 北京
        (121.4737, 31.2304),  // 上海
        (113.2644, 23.1291),  // 广州
    ];
    
    // 单线程批量转换
    let results: Vec<_> = cities.iter()
        .map(|&coord| proj.project(coord, false))
        .collect::<Result<_, _>>()?;
    println!("单线程批量结果: {:?}", results);
    
    // 5. 使用rayon并行处理
    let par_results: Vec<_> = cities.par_iter()
        .map(|&coord| proj.project(coord, false))
        .collect::<Result<_, _>>()?;
    println!("并行处理结果: {:?}", par_results);
    
    // 6. 错误处理示例
    match proj.project((181.0, 91.0), false) {
        Ok(_) => unreachable!(),
        Err(e) => println!("捕获到预期错误: {}", e),
    }
    
    Ok(())
}

这个完整示例展示了:

  1. 使用EPSG代码创建转换器
  2. 单个坐标的正向转换
  3. 反向转换验证
  4. 批量坐标转换
  5. 使用rayon的并行处理
  6. 错误处理机制

要运行此示例,需要在Cargo.toml中添加:

[dependencies]
proj-sys = "0.24"
rayon = "1.5"
回到顶部