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"
- 确保PostgreSQL数据库已安装PostGIS扩展:
CREATE EXTENSION postgis;
- 运行程序前请根据实际情况修改数据库连接参数。
这个示例展示了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", ¢ral_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(())
}
代码说明
-
数据库连接:使用tokio-postgres建立异步连接
-
几何对象创建:
- 点(Point): 表示单个坐标点
- 线(LineString): 由一系列点组成的线
- 多边形(Polygon): 由环(闭合线)组成的多边形
-
空间查询:
- 查询特定类型的几何要素
- 计算两点间距离
- 创建缓冲区
-
几何操作:
- 从WKT(文本)创建几何对象
- 计算几何中心点
-
注意事项:
- 所有几何对象使用相同的SRID(4326表示WGS84坐标系)
- 使用ST_AsText函数将几何对象转为可读文本
- 使用::geography类型进行精确距离计算(单位为米)
这个示例展示了postgis库的核心功能,包括几何对象的创建、存储、查询和分析。实际使用时,可以根据需要调整查询条件和几何操作。