Rust地理空间数据处理库postgis的使用,支持PostgreSQL地理信息系统扩展的高效操作

Rust地理空间数据处理库postgis的使用,支持PostgreSQL地理信息系统扩展的高效操作

rust-postgis是一个rust-postgres的扩展,增加了对PostGIS的支持。

主要特性

  • PostGIS类型支持
  • 支持GCJ02坐标系(中国大陆官方使用)
  • 支持Tiny WKB (TWKB)格式

使用示例

基本使用示例

use postgres::{Client, NoTls};
use postgis::{ewkb, LineString};

fn main() {
    // 连接到PostgreSQL数据库
    let mut client = Client::connect("host=localhost user=postgres", NoTls).unwrap();
    
    // 查询公交线路数据
    for row in &client.query("SELECT * FROM busline", &[]).unwrap() {
        // 获取线路几何数据(LineString类型)
        let route: ewkb::LineString = row.get("route");
        // 获取最后一个站点
        let last_stop = route.points().last().unwrap();
        // 将站点数据插入到stops表
        let _ = client.execute("INSERT INTO stops (stop) VALUES ($1)", &[&last_stop]);
    }
}

处理NULL值

let route = row.try_get::<_, Option<ewkb::LineString>>("route");
match route {
    Ok(Some(geom)) => { println!("{:?}", geom) }
    Ok(None) => { /* 处理NULL值 */ }
    Err(err) => { println!("Error: {}", err) }
}

写入其他几何类型到PostGIS

rust-postgis支持将实现了以下trait的几何类型写入PostGIS:

  • Point, LineString
  • AsEwkbPoint, AsEwkbLineString

以下是从TWKB读取几何数据并以EWKB格式写回的示例:

use postgis::twkb;
use postgis::LineString;

for row in &conn.query("SELECT ST_AsTWKB(route) FROM busline", &[]).unwrap() {
    // 读取TWKB格式的线路数据
    let route: twkb::LineString = row.get(0);
    // 获取最后一个站点
    let last_stop = route.points().last().unwrap();
    // 将站点数据以EWKB格式插入到stops表
    let _ = conn.execute("INSERT INTO stops (stop) VALUES ($1)", &[&last_stop.as_ewkb()]);
}

单元测试

需要PostgreSQL连接的单元测试默认会被忽略。要运行数据库测试,需要在环境变量DBCONN中声明数据库连接。例如:

export DBCONN=postgresql://user@localhost/testdb

然后运行测试:

cargo test -- --ignored

完整示例代码

以下是一个完整的Rust程序示例,演示了如何使用rust-postgis库与PostgreSQL/PostGIS进行交互:

use postgres::{Client, NoTls};
use postgis::{ewkb, Point, LineString};
use postgis::srs::Srs;
use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    // 1. 连接到PostgreSQL数据库
    let mut client = Client::connect(
        "host=localhost dbname=gis_db user=postgres password=yourpassword", 
        NoTls
    )?;

    // 2. 创建测试表(如果不存在)
    client.execute(
        "CREATE TABLE IF NOT EXISTS spatial_test (
            id SERIAL PRIMARY KEY,
            name VARCHAR(100),
            geom GEOMETRY(POINT, 4326),
            path GEOMETRY(LINESTRING, 4326)
        )", 
        &[]
    )?;

    // 3. 插入点数据
    let point = ewkb::Point {
        x: 116.404,
        y: 39.915,
        srid: Some(4326)  // WGS84坐标系
    };
    
    client.execute(
        "INSERT INTO spatial_test (name, geom) VALUES ($1, $2)",
        &[&"天安门", &point]
    )?;

    // 4. 插入线数据
    let line = ewkb::LineString {
        points: vec![
            ewkb::Point { x: 116.404, y: 39.915, srid: Some(4326) },
            ewkb::Point { x: 116.408, y: 39.918, srid: Some(4326) },
            ewkb::Point { x: 116.410, y: 39.920, srid: Some(4326) }
        ],
        srid: Some(4326)
    };
    
    client.execute(
        "INSERT INTO spatial_test (name, path) VALUES ($1, $2)",
        &[&"步行路线", &line]
    )?;

    // 5. 查询并处理空间数据
    for row in client.query("SELECT id, name, geom, path FROM spatial_test", &[])? {
        let id: i32 = row.get(0);
        let name: String極限如下:

1. 在Cargo.toml中添加依赖:
```toml
[dependencies]
postgis = "0.9.0"
postgres = "0.19"
  1. 确保PostgreSQL数据库已安装PostGIS扩展:
CREATE EXTENSION postgis;
  1. 运行程序前请根据实际情况修改数据库连接参数。

这个示例展示了rust-postgis库的基本用法,包括:

  • 连接PostgreSQL/PostGIS数据库
  • 创建空间数据表
  • 插入点、线等空间数据
  • 查询和处理空间数据
  • 使用PostGIS空间函数进行查询

通过rust-postgis库,Rust开发者可以方便地在应用程序中处理地理空间数据,并与PostgreSQL/PostGIS进行高效交互。


1 回复

Rust地理空间数据处理库postgis的使用

示例代码

以下是基于postgis库的完整示例代码,展示了如何连接数据库、创建几何对象、执行空间查询和几何操作:

use postgis::{ewkb::{Geometry, GeometryType}, LineString, Point, Polygon};
use tokio_postgres::{NoTls, Client};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. 连接到PostgreSQL数据库
    let (client, connection) = tokio_postgres::connect(
        "host=localhost user=postgres dbname=gis_db",
        NoTls,
    ).await?;

    // 处理连接任务
    tokio::spawn(async move {
        if let Err(e) = connection.await {
            eprintln!("connection error: {}", e);
        }
    });

    // 2. 创建几何对象
    // 2.1 创建点(纽约中央公园坐标)
    let central_park = Point {
        x: -73.935242,
        y: 40.730610,
        srid: Some(4326),  // WGS84坐标系统
    };

    // 2.2 创建线(简单对角线)
    let diagonal_line = LineString {
        points: vec![
            Point { x: 0.0, y: 0.0, srid: Some(4326) },
            Point { x: 1.0, y: 1.0, srid: Some(4326) },
            Point { x: 2.0, y: 2.0, srid: Some(4326) },
        ],
        srid: Some(4326),
    };

    // 2.3 创建多边形(正方形)
    let square_polygon = Polygon {
        rings: vec![vec![
            Point { x: 0.0, y: 0.0, srid: Some(4326) },
            Point { x: 0.0, y: 1.0, srid: Some(4326) },
            Point { x: 1.0, y: 1.0, srid: Some(4326) },
            Point { x: 1.0, y: 0.0, srid: Some(4326) },
            Point { x: 0.0, y: 0.0, srid: Some(4326) },
        ]],
        srid: Some(4326),
    };

    // 3. 创建表(如果不存在)
    client.execute(
        "CREATE TABLE IF NOT EXISTS locations (
            id SERIAL PRIMARY KEY,
            name VARCHAR(100) NOT NULL,
            geom GEOMETRY(GEOMETRY, 4326)
        )",
        &[]
    ).await?;

    // 4. 插入数据
    client.execute(
        "INSERT INTO locations (name, geom) VALUES ($1, $2)",
        &[&"Central Park", &central_park]
    ).await?;

    client.execute(
        "INSERT INTO locations (name, geom) VALUES ($1, $2)",
        &[&"Diagonal Line", &diagonal_line]
    ).await?;

    client.execute(
        "INSERT INTO locations (name, geom) VALUES ($1, $2)",
        &[&"Square Polygon", &square_polygon]
    ).await?;

    // 5. 空间查询示例
    println!("=== 空间查询示例 ===");
    
    // 5.1 查询所有点要素
    let point_features = client.query(
        "SELECT name, ST_AsText(geom) FROM locations WHERE GeometryType(geom) = 'POINT'",
        &[]
    ).await?;
    
    for row in point_features {
        let name: String = row.get(0);
        let wkt: String = row.get(1);
        println!("点要素: {} - {}", name, wkt);
    }

    // 5.2 计算两个点之间的距离
    let point1 = Point {
        x: -74.0060, 
        y: 40.7128,
        srid: Some(4326)
    };
    
    let point2 = Point {
        x: -73.935242,
        y: 40.730610,
        srid: Some(4326)
    };
    
    let distance = client.query_one(
        "SELECT ST_Distance($1::geography, $2::geography)",
        &[&point1, &point2]
    ).await?;
    
    let distance_meters: f64 = distance.get(0);
    println!("两点之间的距离: {:.2} 米", distance_meters);

    // 5.3 缓冲区分析
    let buffered_area = client.query_one(
        "SELECT ST_AsText(ST_Buffer($1::geography, 500))",  // 500米缓冲区
        &[&point1]
    ).await?;
    
    let buffered_wkt: String = buffered_area.get(0);
    println!("500米缓冲区: {}", buffered_wkt);

    // 6. 几何操作示例
    println!("\n=== 几何操作示例 ===");
    
    // 6.1 从WKT创建几何对象
    let wkt_point = "POINT(10 20)";
    let geom: Geometry = client.query_one(
        "SELECT ST_GeomFromText($1, 4326)",
        &[&wkt_point]
    ).await?.get(0);
    
    if let GeometryType::Point = geom.geometry_type {
        if let Some(pt) = geom.point {
            println!("从WKT创建的点: ({}, {})", pt.x, pt.y);
        }
    }

    // 6.2 计算几何中心点
    let center: Geometry = client.query_one(
        "SELECT ST_Centroid(geom) FROM locations WHERE name = 'Square Polygon'",
        &[]
    ).await?.get(0);
    
    if let GeometryType::Point = center.geometry_type {
        if let Some(centroid) = center.point {
            println!("正方形中心点: ({}, {})", centroid.x, centroid.y);
        }
    }

    Ok(())
}

代码说明

  1. 数据库连接:使用tokio-postgres建立异步连接

  2. 几何对象创建

    • 点(Point): 表示单个坐标点
    • 线(LineString): 由一系列点组成的线
    • 多边形(Polygon): 由环(闭合线)组成的多边形
  3. 空间查询

    • 查询特定类型的几何要素
    • 计算两点间距离
    • 创建缓冲区
  4. 几何操作

    • 从WKT(文本)创建几何对象
    • 计算几何中心点
  5. 注意事项

    • 所有几何对象使用相同的SRID(4326表示WGS84坐标系)
    • 使用ST_AsText函数将几何对象转为可读文本
    • 使用::geography类型进行精确距离计算(单位为米)

这个示例展示了postgis库的核心功能,包括几何对象的创建、存储、查询和分析。实际使用时,可以根据需要调整查询条件和几何操作。

回到顶部