Project Icon

geozero

Rust地理空间数据零拷贝处理库

GeoZero是一个Rust编写的地理空间数据处理库,通过零拷贝技术实现高效的数据读写。该库支持GeoJSON、WKB、WKT等多种格式,提供数据转换、处理和渲染API。GeoZero集成了PostGIS,便于与数据库交互。它可以处理从简单几何操作到复杂空间分析的各种任务,适用于地理信息系统的开发。

GeoZero

GitHub CI构建 crates.io版本 docs.rs文档 Discord聊天

零拷贝读写地理空间数据。

GeoZero定义了一个用于读取地理空间数据格式的API,无需中间表示。它定义了可以实现的特征,用于读取和转换为任意格式或直接渲染几何图形。

支持的几何类型:

  • OGC简单要素
  • SQL-MM第3部分定义的圆弧
  • TIN(不规则三角网)

支持的维度:X, Y, Z, M, T

可用实现

格式读取写入备注
GeoJSON
GEOS
GDAL
WKB支持rust-postgresSQLxDiesel的PostGIS几何图形。同时也支持SQLx的GeoPackage几何图形。
WKT
CSV
SVG
geo-types
MVT(Mapbox矢量瓦片)
GPX
Shapefile通过geozero-shpcrate可用。
FlatGeobuf通过flatgeobufcrate可用。
GeoArrow通过geoarrowcrate可用。
GeoParquet通过geoarrowcrate可用。

应用

转换API

将GeoJSON多边形转换为geo-types并计算质心:

let geojson = GeoJson(r#"{"type": "Polygon", "coordinates": [[[0, 0], [10, 0], [10, 6], [0, 6], [0, 0]]]}"#);
if let Ok(Geometry::Polygon(poly)) = geojson.to_geo() {
    assert_eq!(poly.centroid().unwrap(), Point::new(5.0, 3.0));
}

完整源代码:geo_types.rs

将GeoJSON转换为GEOS预处理几何图形:

let geojson = GeoJson(r#"{"type": "Polygon", "coordinates": [[[0, 0], [10, 0], [10, 6], [0, 6], [0, 0]]]}"#);
let geom = geojson.to_geos().expect("GEOS转换失败");
let prepared_geom = geom.to_prepared_geom().expect("to_prepared_geom失败");
let geom2 = geos::Geometry::new_from_wkt("POINT (2.5 2.5)").expect("无效几何图形");
assert_eq!(prepared_geom.contains(&geom2), Ok(true));

完整源代码:geos.rs

将FlatGeobuf子集读取为GeoJSON:

let mut file = BufReader::new(File::open("countries.fgb")?);
let mut fgb = FgbReader::open(&mut file)?.select_bbox(8.8, 47.2, 9.5, 55.3)?;
println!("{}", fgb.to_json()?);

完整源代码:geojson.rs

将FlatGeobuf数据读取为geo-types几何图形,并使用polylabel-rs计算标签位置:

let mut file = BufReader::new(File::open("countries.fgb")?);
let mut fgb = FgbReader::open(&mut file)?.select_all()?;
while let Some(feature) = fgb.next()? {
    let name: String = feature.property("name").unwrap();
    if let Ok(Geometry::MultiPolygon(mpoly)) = feature.to_geo() {
        if let Some(poly) = &mpoly.0.iter().next() {
            let label_pos = polylabel(&poly, &0.10).unwrap();
            println!("{name}: {label_pos:?}");
        }
    }
}

完整源代码:polylabel.rs

PostGIS使用示例

使用rust-postgres选择和插入geo-types几何图形。需要with-postgis-postgres特性:

let mut client = Client::connect(&std::env::var("DATABASE_URL").unwrap(), NoTls)?;

let row = client.query_one(
    "SELECT 'SRID=4326;POLYGON ((0 0, 2 0, 2 2, 0 2, 0 0))'::geometry",
    &[],
)?;

let value: wkb::Decode<geo_types::Geometry<f64>> = row.get(0);
if let Some(geo_types::Geometry::Polygon(poly)) = value.geometry {
    assert_eq!(
        *poly.exterior(),
        vec![(0.0, 0.0), (2.0, 0.0), (2.0, 2.0), (0.0, 2.0), (0.0, 0.0)].into()
    );
}

// 插入几何图形
let geom: geo_types::Geometry<f64> = geo::Point::new(1.0, 3.0).into();
let _ = client.execute(
    "INSERT INTO point2d (datetimefield,geom) VALUES(now(),ST_SetSRID($1,4326))",
    &[&wkb::Encode(geom)],
);

使用SQLx选择和插入geo-types几何图形。需要with-postgis-sqlx特性:

let pool = PgPoolOptions::new()
    .max_connections(5)
    .connect(&env::var("DATABASE_URL").unwrap())
    .await?;

让 row: (wkb::Decode<geo_types::Geometry>,) = sqlx::query_as("SELECT 'SRID=4326;POLYGON ((0 0, 2 0, 2 2, 0 2, 0 0))'::geometry") .fetch_one(&pool) .await?; let value = row.0; if let Some(geo_types::Geometry::Polygon(poly)) = value.geometry { assert_eq!( *poly.exterior(), vec![(0.0, 0.0), (2.0, 0.0), (2.0, 2.0), (0.0, 2.0), (0.0, 0.0)].into() ); }

// 插入几何体 let geom: geo_types::Geometry = geo::Point::new(10.0, 20.0).into(); let _ = sqlx::query( "INSERT INTO point2d (datetimefield,geom) VALUES(now(),ST_SetSRID($1,4326))", ) .bind(wkb::Encode(geom)) .execute(&pool) .await?;


使用编译时验证需要[类型重写](https://docs.rs/sqlx/latest/sqlx/macro.query.html#force-a-differentcustom-type):
```rust,ignore
let _ = sqlx::query!(
    "INSERT INTO point2d (datetimefield, geom) VALUES(now(), $1::geometry)",
    wkb::Encode(geom) as _
)
.execute(&pool)
.await?;

struct PointRec {
    pub geom: wkb::Decode<geo_types::Geometry<f64>>,
    pub datetimefield: Option<OffsetDateTime>,
}
let rec = sqlx::query_as!(
    PointRec,
    r#"SELECT datetimefield, geom as "geom!: _" FROM point2d"#
)
.fetch_one(&pool)
.await?;
assert_eq!(
    rec.geom.geometry.unwrap(),
    geo::Point::new(10.0, 20.0).into()
);

完整源代码:postgis.rs

处理API

计算输入几何体的顶点数:

struct VertexCounter(u64);

impl GeomProcessor for VertexCounter {
    fn xy(&mut self, _x: f64, _y: f64, _idx: usize) -> Result<()> {
        self.0 += 1;
        Ok(())
    }
}

let mut vertex_counter = VertexCounter(0);
geometry.process(&mut vertex_counter, GeometryType::MultiPolygon)?;

完整源代码:geozero-api.rs

寻找3D多边形中的最大高度:

struct MaxHeightFinder(f64);

impl GeomProcessor for MaxHeightFinder {
    fn coordinate(&mut self, _x: f64, _y: f64, z: Option<f64>, _m: Option<f64>, _t: Option<f64>, _tm: Option<u64>, _idx: usize) -> Result<()> {
        if let Some(z) = z {
            if z > self.0 {
                self.0 = z
            }
        }
        Ok(())
    }
}

let mut max_finder = MaxHeightFinder(0.0);
while let Some(feature) = fgb.next()? {
    let geometry = feature.geometry().unwrap();
    geometry.process(&mut max_finder, GeometryType::MultiPolygon)?;
}

完整源代码:geozero-api.rs

渲染多边形:

struct PathDrawer<'a> {
    canvas: &'a mut CanvasRenderingContext2D,
    path: Path2D,
}

impl<'a> GeomProcessor for PathDrawer<'a> {
    fn xy(&mut self, x: f64, y: f64, idx: usize) -> Result<()> {
        if idx == 0 {
            self.path.move_to(vec2f(x, y));
        } else {
            self.path.line_to(vec2f(x, y));
        }
        Ok(())
    }
    fn linestring_end(&mut self, _tagged: bool, _idx: usize) -> Result<()> {
        self.path.close_path();
        self.canvas.fill_path(
            mem::replace(&mut self.path, Path2D::new()),
            FillRule::Winding,
        );
        Ok(())
    }
}

完整源代码:flatgeobuf-gpu

使用异步HTTP客户端读取FlatGeobuf数据集,应用边界框过滤器并转换为GeoJSON:

let url = "https://flatgeobuf.org/test/data/countries.fgb";
let mut fgb = HttpFgbReader::open(url)
    .await?
    .select_bbox(8.8, 47.2, 9.5, 55.3)
    .await?;

let mut fout = BufWriter::new(File::create("countries.json")?);
let mut json = GeoJsonWriter::new(&mut fout);
fgb.process_features(&mut json).await?;

完整源代码:geojson.rs

使用kdbush创建KD树索引:

struct PointIndex {
    pos: usize,
    index: KDBush,
}

impl geozero::GeomProcessor for PointIndex {
    fn xy(&mut self, x: f64, y: f64, _idx: usize) -> Result<()> {
        self.index.add_point(self.pos, x, y);
        self.pos += 1;
        Ok(())
    }
}

let mut points = PointIndex {
    pos: 0,
    index: KDBush::new(1249, DEFAULT_NODE_SIZE),
};
read_geojson_geom(&mut f, &mut points)?;
points.index.build_index();

完整源代码:kdbush.rs

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号