znlgis 博客

GIS开发与技术分享

第八章:矢量分析步骤详解

8.1 概述

矢量分析步骤是 GeoPipeAgent 中最常用的步骤类别,涵盖了 GIS 中常见的空间分析操作。所有矢量步骤都通过 Backend 执行,支持 gdal_pythongdal_cliqgis_process 三种后端。

GeoPipeAgent 提供 7 个矢量分析步骤:

Step ID 名称 说明
vector.buffer 缓冲区分析 生成几何缓冲区
vector.clip 矢量裁剪 用裁剪范围裁剪数据
vector.reproject 投影转换 CRS 坐标系转换
vector.dissolve 融合 按字段融合要素
vector.simplify 几何简化 Douglas-Peucker 简化
vector.query 属性查询 按属性条件筛选
vector.overlay 叠加分析 两图层叠加运算

8.2 vector.buffer — 缓冲区分析

8.2.1 功能说明

对输入的矢量数据中每个要素生成指定距离的缓冲区(Buffer)。缓冲区分析是 GIS 中最基本的空间分析操作之一,常用于:

  • 道路噪音影响范围分析
  • 水源保护区划定
  • 设施服务范围分析

8.2.2 参数

参数 类型 必需 默认值 说明
input geodataframe 输入矢量数据
distance number 缓冲区距离(单位取决于 CRS)
cap_style string round 端点样式:round/flat/square

8.2.3 输出

属性 说明
output 缓冲区结果 GeoDataFrame
stats.feature_count 要素数量
stats.total_area 缓冲区总面积

8.2.4 使用示例

基本缓冲区:

- id: buffer
  use: vector.buffer
  params:
    input: "$read.output"
    distance: 500

指定端点样式:

- id: buffer
  use: vector.buffer
  params:
    input: "$read.output"
    distance: 100
    cap_style: "flat"       # 平头端点(适合道路缓冲区)

8.2.5 注意事项

  • 距离单位取决于输入数据的 CRS。如果 CRS 是地理坐标系(如 EPSG:4326),距离单位是度;如果是投影坐标系(如 EPSG:3857),距离单位是米。建议在缓冲区分析前先进行投影转换。
  • cap_style 的三种选项:
    • round:圆形端点(默认,最常用)
    • flat:平头端点(线要素的端点被截断)
    • square:方形端点

8.2.6 典型工作流

pipeline:
  name: "道路缓冲区分析"
  steps:
    - id: read
      use: io.read_vector
      params:
        path: "data/roads.shp"
    - id: reproject
      use: vector.reproject
      params:
        input: "$read.output"
        target_crs: "EPSG:3857"    # 投影到米单位的坐标系
    - id: buffer
      use: vector.buffer
      params:
        input: "$reproject.output"
        distance: 500               # 500 米
    - id: save
      use: io.write_vector
      params:
        input: "$buffer.output"
        path: "output/road_buffer.geojson"

8.3 vector.clip — 矢量裁剪

8.3.1 功能说明

使用裁剪范围(clip geometry)裁剪输入数据。只保留落在裁剪范围内的部分。

8.3.2 参数

参数 类型 必需 默认值 说明
input geodataframe 待裁剪的矢量数据
clip_layer geodataframe 裁剪范围数据

8.3.3 使用示例

pipeline:
  name: "矢量裁剪"
  steps:
    - id: read-data
      use: io.read_vector
      params:
        path: "data/roads.shp"
    - id: read-boundary
      use: io.read_vector
      params:
        path: "data/city_boundary.shp"
    - id: clip
      use: vector.clip
      params:
        input: "$read-data.output"
        clip_layer: "$read-boundary.output"
    - id: save
      use: io.write_vector
      params:
        input: "$clip.output"
        path: "output/clipped_roads.geojson"

8.4 vector.reproject — 投影转换

8.4.1 功能说明

将矢量数据从一个坐标参考系统(CRS)转换到另一个。投影转换是 GIS 分析中非常重要的前处理步骤。

8.4.2 参数

参数 类型 必需 默认值 说明
input geodataframe 输入矢量数据
target_crs string 目标 CRS(如 EPSG:4326

8.4.3 使用示例

转为 Web Mercator:

- id: reproject
  use: vector.reproject
  params:
    input: "$read.output"
    target_crs: "EPSG:3857"

转为 WGS84:

- id: reproject
  use: vector.reproject
  params:
    input: "$read.output"
    target_crs: "EPSG:4326"

8.4.4 常用 CRS

EPSG 代码 名称 说明
EPSG:4326 WGS 84 GPS 坐标系,全球通用
EPSG:3857 Web Mercator Web 地图标准投影
EPSG:4490 CGCS2000 中国大地坐标系
EPSG:4547 CGCS2000 / 3-degree Zone 39 中国 3° 带投影
EPSG:32650 WGS 84 / UTM zone 50N UTM 50 北带

8.5 vector.dissolve — 融合

8.5.1 功能说明

将要素按指定字段进行融合(Dissolve),相同属性值的要素合并为一个。可以指定聚合函数处理其他属性。

8.5.2 参数

参数 类型 必需 默认值 说明
input geodataframe 输入矢量数据
by string 融合字段名(不指定则全部融合为一个要素)
aggfunc string first 聚合函数(first/sum/mean/count 等)

8.5.3 使用示例

按用地类型融合:

- id: dissolve
  use: vector.dissolve
  params:
    input: "$read.output"
    by: "landuse_type"
    aggfunc: "first"

全部融合为单个要素:

- id: dissolve
  use: vector.dissolve
  params:
    input: "$read.output"

8.6 vector.simplify — 几何简化

8.6.1 功能说明

使用 Douglas-Peucker 算法简化几何形状,减少顶点数量,适用于需要减小数据量的场景。

8.6.2 参数

参数 类型 必需 默认值 说明
input geodataframe 输入矢量数据
tolerance number 简化容差(单位取决于 CRS)
preserve_topology boolean true 是否保持拓扑关系

8.6.3 使用示例

- id: simplify
  use: vector.simplify
  params:
    input: "$read.output"
    tolerance: 0.001         # 约 100 米(EPSG:4326 下)
    preserve_topology: true

8.6.4 容差选择指南

CRS 类型 容差值示例 效果
地理坐标系(度) 0.0001 约 10 米精度
地理坐标系(度) 0.001 约 100 米精度
投影坐标系(米) 1.0 1 米精度
投影坐标系(米) 10.0 10 米精度

8.7 vector.query — 属性查询

8.7.1 功能说明

使用 Pandas query 表达式筛选满足条件的要素。

8.7.2 参数

参数 类型 必需 默认值 说明
input geodataframe 输入矢量数据
expression string Pandas query 表达式

8.7.3 使用示例

筛选面积大于 1000 的地块:

- id: filter
  use: vector.query
  params:
    input: "$read.output"
    expression: "area_sqm > 1000"

多条件筛选:

- id: filter
  use: vector.query
  params:
    input: "$read.output"
    expression: "type == 'residential' and area > 500"

使用变量:

pipeline:
  variables:
    min_area: 1000
    filter_expression: "area_sqm > 1000"
  steps:
    - id: filter
      use: vector.query
      params:
        input: "$read.output"
        expression: "${filter_expression}"

8.7.4 表达式语法

vector.query 使用 Pandas DataFrame 的 query() 方法,支持以下语法:

操作 示例
比较 area > 1000
等于 type == 'residential'
逻辑与 area > 100 and type == 'park'
逻辑或 type == 'road' or type == 'highway'
包含 type in ['park', 'garden']
字符串方法 name.str.contains('road')

8.8 vector.overlay — 叠加分析

8.8.1 功能说明

对两个矢量图层进行叠加分析,支持交集、并集、差集和对称差集四种运算。

8.8.2 参数

参数 类型 必需 默认值 说明
input geodataframe 输入图层
overlay_layer geodataframe 叠加图层
how string intersection 叠加方式

8.8.3 叠加方式

how 值 名称 说明
intersection 交集 两个图层重叠的部分
union 并集 两个图层的合集
difference 差集 在输入图层中但不在叠加图层中的部分
symmetric_difference 对称差集 两个图层不重叠的部分

8.8.4 使用示例

求两图层交集:

pipeline:
  name: "叠加分析"
  steps:
    - id: load-landuse
      use: io.read_vector
      params:
        path: "data/landuse.shp"
    - id: load-flood
      use: io.read_vector
      params:
        path: "data/flood_zone.shp"
    - id: overlay
      use: vector.overlay
      params:
        input: "$load-landuse.output"
        overlay_layer: "$load-flood.output"
        how: "intersection"
    - id: save
      use: io.write_vector
      params:
        input: "$overlay.output"
        path: "output/landuse_in_flood.geojson"

求差集:

- id: difference
  use: vector.overlay
  params:
    input: "$parks.output"
    overlay_layer: "$buildings.output"
    how: "difference"

8.9 矢量步骤与 Backend 的关系

所有矢量步骤都通过 Backend 执行实际的 GIS 操作。步骤函数负责参数获取和结果封装,具体的空间计算委托给 Backend:

# 步骤函数模式
def vector_buffer(ctx: StepContext) -> StepResult:
    gdf = ctx.input("input")          # 1. 获取参数
    distance = ctx.param("distance")

    result = ctx.backend.buffer(gdf, distance)  # 2. 委托给 Backend

    return StepResult(output=result, stats={...})  # 3. 封装结果

这意味着用户可以通过指定不同的 Backend 来改变步骤的内部实现:

# 使用默认后端(gdal_python)
- id: buffer
  use: vector.buffer
  params:
    input: "$read.output"
    distance: 500

# 使用 GDAL CLI 后端(适合大文件)
- id: buffer
  use: vector.buffer
  params:
    input: "$read.output"
    distance: 500
  backend: gdal_cli

# 使用 QGIS 后端
- id: buffer
  use: vector.buffer
  params:
    input: "$read.output"
    distance: 500
  backend: qgis_process

8.10 综合案例:完整矢量分析流水线

pipeline:
  name: "城市公园可达性分析"
  description: "分析城市公园的500米服务范围覆盖情况"
  variables:
    parks_path: "data/parks.shp"
    buildings_path: "data/buildings.shp"
    buffer_distance: 500

  steps:
    # 读取数据
    - id: read-parks
      use: io.read_vector
      params:
        path: "${parks_path}"

    - id: read-buildings
      use: io.read_vector
      params:
        path: "${buildings_path}"

    # 投影转换
    - id: reproject-parks
      use: vector.reproject
      params:
        input: "$read-parks.output"
        target_crs: "EPSG:3857"

    - id: reproject-buildings
      use: vector.reproject
      params:
        input: "$read-buildings.output"
        target_crs: "EPSG:3857"

    # 生成公园缓冲区
    - id: park-buffer
      use: vector.buffer
      params:
        input: "$reproject-parks.output"
        distance: "${buffer_distance}"

    # 融合缓冲区
    - id: dissolve-buffer
      use: vector.dissolve
      params:
        input: "$park-buffer.output"

    # 查找在缓冲区内的建筑
    - id: covered-buildings
      use: vector.overlay
      params:
        input: "$reproject-buildings.output"
        overlay_layer: "$dissolve-buffer.output"
        how: "intersection"

    # 保存结果
    - id: save
      use: io.write_vector
      params:
        input: "$covered-buildings.output"
        path: "output/park_coverage.geojson"

  outputs:
    result: "$save.output"
    total_parks: "$read-parks.feature_count"
    covered_buildings: "$covered-buildings.feature_count"
    total_buildings: "$read-buildings.feature_count"