矢量数据处理

第六章 矢量数据处理

6.1 矢量数据基础

6.1.1 矢量数据模型

矢量数据由几何对象和属性组成:

几何类型

类型 WKB类型 说明
Point 1 单点
LineString 2 单线
Polygon 3 单面
MultiPoint 4 多点
MultiLineString 5 多线
MultiPolygon 6 多面
GeometryCollection 7 几何集合

带Z值和M值的变体

  • PointZ, LineStringZ, PolygonZ(带高程)
  • PointM, LineStringM, PolygonM(带测量值)
  • PointZM, LineStringZM, PolygonZM(同时带Z和M)

6.1.2 要素结构

要素 (Feature)
├── 几何 (Geometry)
│   ├── 坐标点列表
│   └── 空间参考
└── 属性 (Attributes)
    ├── 字段1: 值1
    ├── 字段2: 值2
    └── ...

6.1.3 PyQGIS要素操作

from qgis.core import (
    QgsVectorLayer, QgsFeature, QgsGeometry, 
    QgsPointXY, QgsField, QgsFields
)
from qgis.PyQt.QtCore import QVariant

# 获取图层要素
layer = iface.activeLayer()

# 遍历所有要素
for feature in layer.getFeatures():
    # 获取几何
    geom = feature.geometry()
    # 获取属性
    attrs = feature.attributes()
    # 获取特定字段值
    name = feature['name']
    
# 使用请求过滤
from qgis.core import QgsFeatureRequest

# 按属性过滤
request = QgsFeatureRequest().setFilterExpression('"population" > 1000000')
for feature in layer.getFeatures(request):
    print(feature['name'])

# 按范围过滤
from qgis.core import QgsRectangle
extent = QgsRectangle(100, 30, 120, 45)
request = QgsFeatureRequest().setFilterRect(extent)

# 只获取部分字段
request = QgsFeatureRequest().setSubsetOfAttributes(['name', 'population'], layer.fields())

6.2 属性表操作

6.2.1 打开属性表

方法

  • 右键图层 > 打开属性表
  • 快捷键:F6
  • 图层菜单 > 打开属性表

6.2.2 属性表功能

视图模式

  • 表格视图:传统表格显示
  • 表单视图:单要素表单显示

过滤模式

  • 显示所有要素
  • 显示选中的要素
  • 显示地图上可见的要素
  • 显示已编辑的要素
  • 按条件过滤

常用操作

操作 方法
选择要素 点击行或使用选择工具
缩放到选择 工具栏按钮或快捷键
排序 点击列标题
筛选 使用表达式过滤
编辑 开启编辑模式后修改
添加字段 开启编辑后点击添加
删除字段 选择字段后删除

6.2.3 字段计算器

打开字段计算器

属性表 > 打开字段计算器按钮
或 Ctrl+I

功能

  • 创建新字段
  • 更新现有字段
  • 虚拟字段(不存储)

表达式示例

-- 数值计算
"area_km2" * 100  -- 面积转换

-- 字符串操作
upper("name")     -- 转大写
concat("first_name", ' ', "last_name")  -- 拼接

-- 条件计算
CASE 
    WHEN "population" > 1000000 THEN '大城市'
    WHEN "population" > 100000 THEN '中等城市'
    ELSE '小城市'
END

-- 几何计算
$area           -- 面积(地图单位)
$length         -- 长度(地图单位)
$perimeter      -- 周长
$x, $y          -- 质心坐标

-- 面积转换
$area / 1000000  -- 平方米转平方公里

-- 使用round
round($area / 1000000, 2)

6.2.4 PyQGIS属性操作

from qgis.core import QgsVectorLayer, QgsField, QgsFeature
from qgis.PyQt.QtCore import QVariant

layer = iface.activeLayer()

# 获取字段信息
fields = layer.fields()
for field in fields:
    print(f"{field.name()}: {field.typeName()}")

# 添加字段
layer.startEditing()
layer.addAttribute(QgsField("new_field", QVariant.Double))
layer.commitChanges()

# 删除字段
layer.startEditing()
layer.deleteAttribute(layer.fields().indexOf("old_field"))
layer.commitChanges()

# 更新属性值
layer.startEditing()
for feature in layer.getFeatures():
    layer.changeAttributeValue(feature.id(), 
                               layer.fields().indexOf("new_field"),
                               feature.geometry().area())
layer.commitChanges()

# 使用表达式更新
from qgis.core import QgsExpression, QgsExpressionContext, QgsExpressionContextUtils

expression = QgsExpression('$area / 1000000')
context = QgsExpressionContext()
context.appendScopes(QgsExpressionContextUtils.globalProjectLayerScopes(layer))

layer.startEditing()
for feature in layer.getFeatures():
    context.setFeature(feature)
    value = expression.evaluate(context)
    layer.changeAttributeValue(feature.id(),
                               layer.fields().indexOf("area_km2"),
                               value)
layer.commitChanges()

6.3 选择与查询

6.3.1 交互式选择

选择工具

  • 按矩形选择
  • 按多边形选择
  • 按徒手圈选
  • 按圆形选择
  • 按要素选择

修饰键

  • Shift:添加到选择
  • Ctrl:从选择中移除
  • Ctrl+Shift:与现有选择交集

6.3.2 按表达式选择

矢量 > 研究工具 > 按表达式选择
或属性表中的"按表达式选择"按钮

表达式示例

-- 简单条件
"population" > 1000000

-- 多条件
"type" = 'city' AND "population" > 500000

-- 文本匹配
"name" LIKE '%北京%'
"name" ILIKE '%beijing%'  -- 不区分大小写

-- 空值判断
"description" IS NULL
"description" IS NOT NULL

-- 列表匹配
"code" IN ('110000', '120000', '310000')

-- 空间条件
within($geometry, geom_from_wkt('POLYGON((100 30, 120 30, 120 45, 100 45, 100 30))'))

6.3.3 按位置选择

矢量 > 研究工具 > 按位置选择

空间谓词

  • 相交 (Intersect)
  • 包含 (Contain)
  • 被包含 (Within)
  • 相等 (Equal)
  • 接触 (Touch)
  • 重叠 (Overlap)
  • 在指定距离内 (Within distance)
  • 交叉 (Cross)

6.3.4 PyQGIS选择操作

from qgis.core import QgsVectorLayer, QgsFeatureRequest, QgsExpression

layer = iface.activeLayer()

# 按表达式选择
expression = QgsExpression('"population" > 1000000')
layer.selectByExpression(expression.expression())

# 按ID选择
layer.select([1, 2, 3])  # 选择要素ID 1, 2, 3

# 全选
layer.selectAll()

# 反选
layer.invertSelection()

# 取消选择
layer.removeSelection()

# 获取选中要素
selected = layer.selectedFeatures()
for feature in selected:
    print(feature['name'])

# 获取选中要素ID
selected_ids = layer.selectedFeatureIds()

# 按位置选择
from qgis.core import QgsGeometry, QgsPointXY

# 选择与点相交的要素
point = QgsPointXY(116.4, 39.9)
buffer = QgsGeometry.fromPointXY(point).buffer(0.1, 5)

for feature in layer.getFeatures():
    if feature.geometry().intersects(buffer):
        layer.select(feature.id())

6.4 基本地理处理

6.4.1 缓冲区分析

工具位置

矢量 > 地理处理工具 > 缓冲区
Processing工具箱 > 矢量几何 > 缓冲区

参数

  • 输入图层
  • 距离(固定值或字段)
  • 分段数(控制平滑度)
  • 端点样式(圆形/平头/方形)
  • 连接样式
  • 斜接限制
  • 溶解结果

PyQGIS实现

import processing

# 简单缓冲
result = processing.run("native:buffer", {
    'INPUT': '/path/to/input.shp',
    'DISTANCE': 100,
    'SEGMENTS': 5,
    'END_CAP_STYLE': 0,  # 0=Round, 1=Flat, 2=Square
    'JOIN_STYLE': 0,      # 0=Round, 1=Miter, 2=Bevel
    'MITER_LIMIT': 2,
    'DISSOLVE': False,
    'OUTPUT': '/path/to/buffer.shp'
})

# 变距缓冲(按字段)
result = processing.run("native:buffer", {
    'INPUT': layer,
    'DISTANCE': QgsProperty.fromExpression('"buffer_dist"'),
    'SEGMENTS': 5,
    'OUTPUT': 'memory:'
})

6.4.2 裁剪分析

工具位置

矢量 > 地理处理工具 > 裁剪

PyQGIS实现

result = processing.run("native:clip", {
    'INPUT': '/path/to/input.shp',
    'OVERLAY': '/path/to/clip_polygon.shp',
    'OUTPUT': '/path/to/clipped.shp'
})

6.4.3 相交分析

result = processing.run("native:intersection", {
    'INPUT': layer1,
    'OVERLAY': layer2,
    'INPUT_FIELDS': [],   # 空=全部字段
    'OVERLAY_FIELDS': [],
    'OUTPUT': 'memory:'
})

6.4.4 合并分析

# 合并图层
result = processing.run("native:mergevectorlayers", {
    'LAYERS': [layer1, layer2, layer3],
    'CRS': 'EPSG:4326',
    'OUTPUT': 'memory:'
})

6.4.5 融合/溶解

result = processing.run("native:dissolve", {
    'INPUT': layer,
    'FIELD': ['province'],  # 按字段分组
    'OUTPUT': 'memory:'
})

6.4.6 差集分析

result = processing.run("native:difference", {
    'INPUT': layer1,
    'OVERLAY': layer2,
    'OUTPUT': 'memory:'
})

6.4.7 对称差分析

result = processing.run("native:symmetricaldifference", {
    'INPUT': layer1,
    'OVERLAY': layer2,
    'OUTPUT': 'memory:'
})

6.5 几何操作

6.5.1 质心提取

result = processing.run("native:centroids", {
    'INPUT': polygon_layer,
    'ALL_PARTS': False,
    'OUTPUT': 'memory:'
})

6.5.2 凸包

result = processing.run("native:convexhull", {
    'INPUT': layer,
    'OUTPUT': 'memory:'
})

6.5.3 最小边界几何

# 最小外接矩形
result = processing.run("native:orientedminimumboundingbox", {
    'INPUT': layer,
    'OUTPUT': 'memory:'
})

# 最小外接圆
result = processing.run("native:minimumenclosingcircle", {
    'INPUT': layer,
    'OUTPUT': 'memory:'
})

# 边界框
result = processing.run("native:boundingboxes", {
    'INPUT': layer,
    'OUTPUT': 'memory:'
})

6.5.4 简化几何

result = processing.run("native:simplifygeometries", {
    'INPUT': layer,
    'METHOD': 0,      # 0=Distance, 1=SnapToGrid, 2=Visvalingam
    'TOLERANCE': 10,
    'OUTPUT': 'memory:'
})

6.5.5 平滑几何

result = processing.run("native:smoothgeometry", {
    'INPUT': layer,
    'ITERATIONS': 3,
    'OFFSET': 0.25,
    'MAX_ANGLE': 180,
    'OUTPUT': 'memory:'
})

6.5.6 多边形转线

result = processing.run("native:polygonstolines", {
    'INPUT': polygon_layer,
    'OUTPUT': 'memory:'
})

6.5.7 线转多边形

result = processing.run("native:linestopolygons", {
    'INPUT': line_layer,
    'OUTPUT': 'memory:'
})

6.5.8 点转线

result = processing.run("native:pointstopath", {
    'INPUT': point_layer,
    'ORDER_FIELD': 'sequence',
    'GROUP_FIELD': 'track_id',
    'OUTPUT': 'memory:'
})

6.5.9 分解多部件几何

result = processing.run("native:multiparttosingleparts", {
    'INPUT': layer,
    'OUTPUT': 'memory:'
})

6.5.10 收集几何

result = processing.run("native:collect", {
    'INPUT': layer,
    'FIELD': ['group_field'],
    'OUTPUT': 'memory:'
})

6.6 空间连接

6.6.1 按位置连接属性

result = processing.run("native:joinattributesbylocation", {
    'INPUT': target_layer,
    'JOIN': join_layer,
    'PREDICATE': [0],     # 0=Intersects, 1=Contains, 2=Equals等
    'JOIN_FIELDS': [],    # 空=全部
    'METHOD': 0,          # 0=一对多, 1=取第一个, 2=取最大重叠
    'DISCARD_NONMATCHING': False,
    'PREFIX': '',
    'OUTPUT': 'memory:'
})

6.6.2 按位置汇总

result = processing.run("native:joinbylocationsummary", {
    'INPUT': target_layer,
    'JOIN': join_layer,
    'PREDICATE': [0],
    'JOIN_FIELDS': ['population'],
    'SUMMARIES': [5, 6],  # 5=Sum, 6=Mean
    'DISCARD_NONMATCHING': False,
    'OUTPUT': 'memory:'
})

6.6.3 按字段值连接

result = processing.run("native:joinattributestable", {
    'INPUT': target_layer,
    'FIELD': 'code',
    'INPUT_2': join_table,
    'FIELD_2': 'code',
    'FIELDS_TO_COPY': [],
    'METHOD': 1,          # 0=一对多, 1=取第一个
    'DISCARD_NONMATCHING': False,
    'PREFIX': '',
    'OUTPUT': 'memory:'
})

6.7 空间统计

6.7.1 要素计数

result = processing.run("native:countpointsinpolygon", {
    'POLYGONS': polygon_layer,
    'POINTS': point_layer,
    'WEIGHT': '',
    'CLASSFIELD': '',
    'FIELD': 'NUMPOINTS',
    'OUTPUT': 'memory:'
})

6.7.2 最近邻分析

result = processing.run("native:nearestneighbouranalysis", {
    'INPUT': point_layer,
    'OUTPUT_HTML_FILE': '/path/to/report.html'
})

6.7.3 距离矩阵

result = processing.run("qgis:distancematrix", {
    'INPUT': point_layer1,
    'INPUT_FIELD': 'id',
    'TARGET': point_layer2,
    'TARGET_FIELD': 'id',
    'MATRIX_TYPE': 0,     # 0=线性, 1=标准, 2=概要
    'NEAREST_POINTS': 0,  # 0=全部
    'OUTPUT': 'memory:'
})

6.7.4 基本统计

result = processing.run("qgis:basicstatisticsforfields", {
    'INPUT_LAYER': layer,
    'FIELD_NAME': 'population',
    'OUTPUT_HTML_FILE': '/path/to/stats.html'
})

# 结果包含:计数、唯一值、空值、最小、最大、范围、总和、平均、中位数、标准差等

6.8 矢量数据创建

6.8.1 创建新图层

通过GUI

图层 > 创建图层 > 新建Shapefile图层
图层 > 创建图层 > 新建GeoPackage图层
图层 > 创建图层 > 新建临时草稿图层

PyQGIS创建

from qgis.core import (
    QgsVectorLayer, QgsField, QgsFeature, 
    QgsGeometry, QgsPointXY, QgsProject,
    QgsVectorFileWriter
)
from qgis.PyQt.QtCore import QVariant

# 创建内存图层
layer = QgsVectorLayer("Point?crs=EPSG:4326", "new_points", "memory")
provider = layer.dataProvider()

# 添加字段
provider.addAttributes([
    QgsField("id", QVariant.Int),
    QgsField("name", QVariant.String),
    QgsField("value", QVariant.Double)
])
layer.updateFields()

# 添加要素
feature = QgsFeature()
feature.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(116.4, 39.9)))
feature.setAttributes([1, "北京", 21.54])
provider.addFeature(feature)

layer.updateExtents()
QgsProject.instance().addMapLayer(layer)

6.8.2 创建规则网格

result = processing.run("native:creategrid", {
    'TYPE': 2,          # 0=Point, 1=Line, 2=Rectangle, 3=Diamond, 4=Hexagon
    'EXTENT': '100,120,30,45',
    'HSPACING': 1,
    'VSPACING': 1,
    'HOVERLAY': 0,
    'VOVERLAY': 0,
    'CRS': 'EPSG:4326',
    'OUTPUT': 'memory:'
})

6.8.3 创建随机点

# 在范围内创建随机点
result = processing.run("native:randompointsinextent", {
    'EXTENT': '100,120,30,45',
    'POINTS_NUMBER': 100,
    'MIN_DISTANCE': 0.1,
    'TARGET_CRS': 'EPSG:4326',
    'OUTPUT': 'memory:'
})

# 在多边形内创建随机点
result = processing.run("native:randompointsinpolygons", {
    'INPUT': polygon_layer,
    'POINTS_NUMBER': 10,
    'MIN_DISTANCE': 0,
    'OUTPUT': 'memory:'
})

6.8.4 泰森多边形

result = processing.run("native:voronoipolygons", {
    'INPUT': point_layer,
    'BUFFER': 0,
    'OUTPUT': 'memory:'
})

6.8.5 德劳内三角网

result = processing.run("native:delaunaytriangulation", {
    'INPUT': point_layer,
    'OUTPUT': 'memory:'
})

6.9 数据导出

6.9.1 导出为文件

GUI方式

右键图层 > 导出 > 另存要素为...

PyQGIS导出

from qgis.core import QgsVectorFileWriter

# 导出为Shapefile
error = QgsVectorFileWriter.writeAsVectorFormat(
    layer,
    "/path/to/output.shp",
    "UTF-8",
    layer.crs(),
    "ESRI Shapefile"
)

# 导出为GeoJSON
error = QgsVectorFileWriter.writeAsVectorFormat(
    layer,
    "/path/to/output.geojson",
    "UTF-8",
    layer.crs(),
    "GeoJSON"
)

# 导出为GeoPackage
options = QgsVectorFileWriter.SaveVectorOptions()
options.driverName = "GPKG"
options.fileEncoding = "UTF-8"
error = QgsVectorFileWriter.writeAsVectorFormatV2(
    layer,
    "/path/to/output.gpkg",
    QgsCoordinateTransformContext(),
    options
)

# 只导出选中要素
options.onlySelectedFeatures = True

6.9.2 导出选项

options = QgsVectorFileWriter.SaveVectorOptions()
options.driverName = "ESRI Shapefile"
options.fileEncoding = "UTF-8"
options.onlySelectedFeatures = True      # 只导出选中
options.filterExtent = QgsRectangle()    # 范围过滤
options.destCRS = QgsCoordinateReferenceSystem("EPSG:32650")  # 转换CRS
options.includeZ = True                   # 包含Z值
options.attributes = [0, 1, 2]           # 指定字段

6.9.3 批量导出

# 按属性分割导出
result = processing.run("native:splitvectorlayer", {
    'INPUT': layer,
    'FIELD': 'province',
    'OUTPUT': '/path/to/output_folder'
})

6.10 小结

本章详细介绍了QGIS中矢量数据处理的各种操作:

关键要点

  1. 理解矢量数据模型和要素结构
  2. 熟练使用属性表和字段计算器
  3. 掌握各种选择和查询方法
  4. 了解常用地理处理工具
  5. 能够进行几何操作和空间连接
  6. 掌握数据创建和导出方法

矢量数据处理是GIS分析的核心内容。


上一章第05章 数据源管理与加载

下一章第07章 栅格数据处理

posted @ 2026-01-08 14:04  我才是银古  阅读(31)  评论(0)    收藏  举报