Python地理数据处理 七:使用OGR处理几何要素

1. 点集

1.1 创建编辑一个点

  OGR中带有额外z坐标的几何要素被认为是2.5D,而不是3D。再OGR进行空间操作时,不考虑z值。
  OGR常量表示的不同几何类型:

在这里插入图片描述

firepit = ogr.Geometry(ogr.wkbPoint)
firepit.AddPoint(10, 21)

x, y = firepit.GetX(), firepit.GetY()
print('{}, {}'.format(x, y))

print(firepit)  # 以WKT格式输出几何对象
vp = VectorPlotter(True)
vp.plot(firepit, 'bo')

# 用SetPoint编辑点
# SetPoint(point,x,y,[z]),point表示编辑的顶点索引
# 点只有一个顶点,所以point为0
firepit.SetPoint(0, 59.5, 13)
print(firepit)

# 创建 2.5D 的点
firepit = ogr.Geometry(ogr.wkbPoint25D)
firepit.AddPoint(59.5, 11.5, 2)
print(firepit)

1.2 创建编辑多个点

import os
from osgeo import ogr
from ospybook.vectorplotter import VectorPlotter

# 创建一个点,添加到多点对象
faucets = ogr.Geometry(ogr.wkbMultiPoint)
faucet = ogr.Geometry(ogr.wkbPoint)
faucet.AddPoint(60, 15)
faucets.AddGeometry(faucet)

# 重用点对象
faucet.AddPoint(70, 30)
faucets.AddGeometry(faucet)
faucet.AddPoint(99, 24.5)
faucets.AddGeometry(faucet)

vp = VectorPlotter(True)
vp.clear()
vp.plot(faucets, 'bo')
vp.zoom(-5)
vp.draw()
print(faucets)

# 运行结果:MULTIPOINT (60 15 0,70 30 0,99.0 24.5 0)

# Edit the coordinates for the second faucet.
faucets.GetGeometryRef(1).AddPoint(75, 32)
vp.plot(faucets, 'k^', 'tmp')
print(faucets)

# 运行结果:MULTIPOINT (60 15 0,75 32 0,99.0 24.5 0)


faucets.GetGeometryRef(1).AddPoint(73, 31)
vp.remove('tmp')
vp.draw()


for i in range(faucets.GetGeometryCount()):
    pt = faucets.GetGeometryRef(i)
    pt.AddPoint(pt.GetX() + 2, pt.GetY())
vp.plot(faucets, 'rs')
vp.zoom(-5)
vp.draw()

在这里插入图片描述

2. 线要素

2.1 创建编辑单线条

  GetPointCount():返回一个几何类型的顶点个数,多点几何类型返回0;
  GetGeometryCount():告诉你有多少个单点几何对象形成一个多点几何类型,若不是多点几何类型,则返回0。

# 创建一个空的几何对象,并添加顶点
# 注意必须按顺序添加顶点

import os
from osgeo import ogr
from ospybook.vectorplotter import VectorPlotter

# 创建2D线
# 由西到东添加顶点 : 54-62-70.5-75
sidewalk = ogr.Geometry(ogr.wkbLineString)
sidewalk.AddPoint(54, 37)
sidewalk.AddPoint(62, 35.5)
sidewalk.AddPoint(70.5, 38)
sidewalk.AddPoint(75, 41.5)

# 绘制几何类型图像
vp = VectorPlotter(True)
vp.plot(sidewalk, 'b-')
vp.draw()
print(sidewalk)
# 结果:LINESTRING (54 37 0,62.0 35.5 0,70.5 38.0 0,75.0 41.5 0)
# 顶点坐标之间用空格分开,顶点之间用逗号隔开


# 用SetPoint()改变最后一个点的坐标
# 索引为3的顶点
sidewalk.SetPoint(3, 76, 41.5)
vp.plot(sidewalk, 'k--', 'tmp')
vp.draw()
print(sidewalk)
# 结果:LINESTRING (54 37 0,62.0 35.5 0,70.5 38.0 0,76.0 41.5 0)


# 将线条向北微调
# 遍历所有顶点,Y坐标加1
for i in range(sidewalk.GetPointCount()):
    sidewalk.SetPoint(i, sidewalk.GetX(i), sidewalk.GetY(i) + 1)
vp.plot(sidewalk, 'r--')
vp.draw()
print(sidewalk)
# 结果:LINESTRING (54 38 0,62.0 36.5 0,70.5 39.0 0,76.0 42.5 0)

  当顶点缺失时,想要添加顶点,可以使用列表的方式进行创建:

# 将线还原到原来的位置
# 查看点坐标,获得一个元组列表
for i in range(sidewalk.GetPointCount()):
    sidewalk.SetPoint(i, sidewalk.GetX(i), sidewalk.GetY(i) - 1)

print(sidewalk.GetPoints())
# 结果:[(54.0, 37.0, 0.0), (62.0, 35.5, 0.0), (70.5, 38.0, 0.0), (76.0, 41.5, 0.0)]


# 在2和3顶点之间插入一个新的顶点
vertices = sidewalk.GetPoints()
vertices[2:2] = [(66.5, 35)]
print(vertices)
# 结果:[(54.0, 37.0, 0.0), (62.0, 35.5, 0.0), (66.5, 35), (70.5, 38.0, 0.0), (76.0, 41.5, 0.0)]


# 用python运算符*,将元组展开为独立参数
# 然后传递给AddPoint()
# 从顶点列表中创建一个新的线几何体
new_sidewalk = ogr.Geometry(ogr.wkbLineString)
for vertex in vertices:
    new_sidewalk.AddPoint(*vertex)
vp.plot(new_sidewalk, 'g:')
vp.draw()

在这里插入图片描述

  python*运算符:
  运算符将元组和列表拆开为单独的元素,可用作为参数传递给函数。

>>> pt = ogr.Geometry(ogr.wkbPoint)
>>> vertex = (10, 20)
>>> pt.AddPoint(*vertex)
>>> pt.AddPoint(vertex)

Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    pt.AddPoint(vertex)
  File "C:\Users\Amazon\AppData\Local\Programs\Python\Python39\lib\site-packages\osgeo\ogr.py", line 6029, in AddPoint
    return _ogr.Geometry_AddPoint(self, *args, **kwargs)
TypeError: Geometry_AddPoint() missing required argument 'y' (pos 3)

  使用 * 操作符将顶点炸开为两个参数,并成功传递给AddPoint。
  不用 * 操作符就只传递一个参数,就是一个元组。但是AddPoint至少有两个参数,x和y,所以执行会失败。

import os
from osgeo import ogr
from ospybook.vectorplotter import VectorPlotter

data_dir = "E:\Google chrome\Download\gis with python\osgeopy data"

ds = ogr.Open(os.path.join(data_dir, 'misc', 'line-example.geojson'))
lyr = ds.GetLayer()
feature = lyr.GetFeature(0)
line = feature.geometry().Clone()
vp.clear()
vp.plot(line, 'b-')

# 在不同的位置添加顶点
# 从末尾开始,避免索引变化问题
vertices = line.GetPoints()
vertices[26:26] = [(87, 57)]
vertices[19:19] = [(95, 38), (97, 43), (101, 42)]
vertices[11:11] = [(121, 18)]
vertices[5:5] = [(67, 32), (74, 30)]
new_line = ogr.Geometry(ogr.wkbLineString)
for vertex in vertices:
    new_line.AddPoint(*vertex)
vp.plot(new_line, 'b--')

# 插入顶点时不需要新建一条线
vertices = sidewalk.GetPoints()
vertices[2:2] = [(66.5, 35)]
for i in range(len(vertices)):
    sidewalk.SetPoint(i, *vertices[i])
vp.plot(sidewalk, 'k-', lw=3)
vp.draw()

在这里插入图片描述
  线图层创建点图层:

# ds:数据源
# line_name:现有线图层名称
# pt_name:新的点图层名称
def line_to_point_layer(ds, line_name, pt_name):
    """从线层中的顶点创建点层"""
    # 如果点图层存在,删除点图层
    if ds.GetLayer(pt_name):
        ds.DeleteLayer(pt_name)

    # 得到线图层和它的空间参考
    line_lyr = ds.GetLayer(line_name)
    sr = line_lyr.GetSpatialRef()

    # 创建一个点图层与线图层相同的sr
    # 并将字段定义从行复制到点图层
    pt_lyr = ds.CreateLayer(pt_name, sr, ogr.wkbPoint)
    pt_lyr.CreateFields(line_lyr.schema)

    # 创建一个特征和几何图形,并反复使用
    pt_feat = ogr.Feature(pt_lyr.GetLayerDefn())
    pt_geom = ogr.Geometry(ogr.wkbPoint)

    # 循环遍历所有行
    for line_feat in line_lyr:

		# 复制属性值
        atts = line_feat.items()

        for fld_name in atts.keys():
            pt_feat.SetField(fld_name, atts[fld_name])

        # 循环遍历这条线的顶点,
        # 对每个顶点,设置点的坐标,添加特性
        # 使用该特性创建点层的新功能
        for coords in line_feat.geometry().GetPoints():
            pt_geom.AddPoint(*coords)
            pt_feat.SetGeometry(pt_geom)
            pt_lyr.CreateFeature(pt_feat)


2.2 创建编辑多线:多线作为一个几何类型

import os
from osgeo import ogr
from ospybook.vectorplotter import VectorPlotter

vp = VectorPlotter(True)

# 创建第一条路径
path1 = ogr.Geometry(ogr.wkbLineString)
path1.AddPoint(61.5, 29)
path1.AddPoint(63, 20)
path1.AddPoint(62.5, 16)
path1.AddPoint(60, 13)

# 创建第二条路径
path2 = ogr.Geometry(ogr.wkbLineString)
path2.AddPoint(60.5, 12)
path2.AddPoint(68.5, 13.5)

# 创建第三条路径
path3 = ogr.Geometry(ogr.wkbLineString)
path3.AddPoint(69.5, 33)
path3.AddPoint(80, 33)
path3.AddPoint(86.5, 22.5)

# 创建多线几何对象,并添加路径
paths = ogr.Geometry(ogr.wkbMultiLineString)
paths.AddGeometry(path1)
paths.AddGeometry(path2)
paths.AddGeometry(path3)

vp.clear()
vp.plot(paths, 'b-')
vp.draw()
print(paths)

MULTILINESTRING ((61.5 29.0 0,63 20 0,62.5 16.0 0,60 13 0),(60.5 12.0 0,68.5 13.5 0),(69.5 33.0 0,80 33 0,86.5 22.5 0))

# 编辑第一条路径的第二个点
paths.GetGeometryRef(0).SetPoint(1, 63, 22)
vp.plot(paths, 'k--', 'tmp')
print(paths)

paths.GetGeometryRef(0).SetPoint(1, 63, 20)
vp.remove('tmp')

# 平移路径
# 获取内部几何对象
for i in range(paths.GetGeometryCount()):
    path = paths.GetGeometryRef(i)
    for j in range(path.GetPointCount()):
        path.SetPoint(j, path.GetX(j) + 2, path.GetY(j) - 3)
vp.plot(paths, 'r--')
vp.draw()

3. 多边形处理

  构成多边形的线不应该接触或者交叉,可用 IsValid() 方法来检查这类问题。注意:没有宽度的多边形是无效的。

在这里插入图片描述

3.1 创建编辑单多边形

  使用 AddPoint() 添加顶点,顶点需要按照顺序添加,但是方向根据使用的数据储存格式而不同。Shapefile外环为顺时针,GeoJSON没有指定顺序。第一个和最后一个顶点必须有相同的坐标,才能形成闭合环。可以使用 CloseRings() 方法闭合环。
  1.创建一个环:

import os
from osgeo import ogr
from ospybook.vectorplotter import VectorPlotter

ring = ogr.Geometry(ogr.wkbLinearRing)
ring.AddPoint(58, 38.5)
ring.AddPoint(53, 6)
ring.AddPoint(99.5, 19)
ring.AddPoint(73, 42)
yard = ogr.Geometry(ogr.wkbPolygon)
yard.AddGeometry(ring)
yard.CloseRings()

vp = VectorPlotter(True)
vp.plot(yard, fill=False, edgecolor='blue')
vp.draw()
print(yard)
POLYGON ((50 40 0,60 10 0,100 25 0,80 40 0,50 40 0))

在这里插入图片描述
  2. 移动整个多边形

ring = yard.GetGeometryRef(0)
for i in range(ring.GetPointCount()):
    ring.SetPoint(i, ring.GetX(i) - 5, ring.GetY(i))
vp.plot(yard, fill=False, ec='red', linestyle='dashed')
vp.draw()

在这里插入图片描述
  3. 将顶点插入到环:

ring = yard.GetGeometryRef(0)
vertices = ring.GetPoints()
vertices[2:3] = ((90, 21), (90, 32))  #  插入两个点
for i in range(len(vertices)):
    ring.SetPoint(i, *vertices[i])
vp.plot(yard, fill=False, ec='black', ls='dotted', linewidth=3)
vp.draw()

在这里插入图片描述
  4. 将多边形转换为线:

# ds:数据源
# line_name:现有线图层名称
# pt_name:新的点图层名称
def line_to_point_layer(ds, line_name, pt_name):
    """从线层中的顶点创建点层"""
    # 如果点图层存在,删除点层
    if ds.GetLayer(pt_name):
        ds.DeleteLayer(pt_name)

    # 得到线层和它的空间参考
    line_lyr = ds.GetLayer(line_name)
    sr = line_lyr.GetSpatialRef()

    # 创建一个与线相同的SR的点层
    # 将字段定义从行复制到点图层
    pt_lyr = ds.CreateLayer(pt_name, sr, ogr.wkbPoint)
    pt_lyr.CreateFields(line_lyr.schema)

    # 创建一个特征和几何图形
    # 可用反复使用
    pt_feat = ogr.Feature(pt_lyr.GetLayerDefn())
    pt_geom = ogr.Geometry(ogr.wkbPoint)

    # 循环遍历所有行
    for line_feat in line_lyr:

        # 将属性值从行复制到新特性
        atts = line_feat.items()
        for fld_name in atts.keys():
            pt_feat.SetField(fld_name, atts[fld_name])

        # 循环遍历这条线的顶点
        # 对于每个顶点,设置几何点的坐标,添加特性
        # 使用该特性创建点层的新功能
        for coords in line_feat.geometry().GetPoints():
            pt_geom.AddPoint(*coords)
            pt_feat.SetGeometry(pt_geom)
            pt_lyr.CreateFeature(pt_feat)


3.2 创建编辑复合多边形

  1. 创建multipolygon:

import os
from osgeo import ogr
from ospybook.vectorplotter import VectorPlotter

# 为第一个花坛创建多边形
box1 = ogr.Geometry(ogr.wkbLinearRing)
box1.AddPoint(87, 25)
box1.AddPoint(89, 25)
box1.AddPoint(89, 24)
box1.AddPoint(87, 24)
garden1 = ogr.Geometry(ogr.wkbPolygon)
garden1.AddGeometry(box1)

# 为第二个花坛创建多边形
box2 = ogr.Geometry(ogr.wkbLinearRing)
box2.AddPoint(89, 21)
box2.AddPoint(91, 21)
box2.AddPoint(91,22)
box2.AddPoint(89,22)
garden2 = ogr.Geometry(ogr.wkbPolygon)
garden2.AddGeometry(box2)

# 创建muliolygon
# 添加两个花坛
gardens = ogr.Geometry(ogr.wkbMultiPolygon)
gardens.AddGeometry(garden1)
gardens.AddGeometry(garden2)
gardens.CloseRings()

vp = VectorPlotter(True)
vp.plot(gardens, fill = False, ec = 'black')
vp.draw()
print(gardens)

在这里插入图片描述
  2. 移动图像:

for i in range(gardens.GetGeometryCount()):
    ring = gardens.GetGeometryRef(i).GetGeometryRef(0)
    for j in range(ring.GetPointCount()):
        ring.SetPoint(j, ring.GetX(j) + 1, ring.GetY(j) + 0.5)
vp.plot(gardens, fill=False, ec='red', ls='dashed')
vp.zoom(-1)
vp.draw()

在这里插入图片描述

3.3 编辑创建空心多边形

  1.创建带洞的多边形:

import os
from osgeo import ogr
from ospybook.vectorplotter import VectorPlotter

# 重建院子轮廓
lot = ogr.Geometry(ogr.wkbLinearRing)
lot.AddPoint(58, 35)
lot.AddPoint(53, 10)
lot.AddPoint(99, 19)
lot.AddPoint(73, 42)

# 给洞构建新的环
house = ogr.Geometry(ogr.wkbLinearRing)
house.AddPoint(65, 29)
house.AddPoint(71, 25)
house.AddPoint(62, 23)
house.AddPoint(60, 15)
house.AddPoint(85, 22)
house.AddPoint(69, 30)

# 添加内环之前添加外环
yard = ogr.Geometry(ogr.wkbPolygon)
yard.AddGeometry(lot)
yard.AddGeometry(house)
yard.CloseRings()

vp = VectorPlotter(True)
vp.clear()
vp.plot(yard, 'blue')
print(yard)
vp.draw()

在这里插入图片描述
  2.平移内环:

for i in range(yard.GetGeometryCount()):
    ring = yard.GetGeometryRef(i)
    for j in range(ring.GetPointCount()):
        ring.SetPoint(j, ring.GetX(j) - 5, ring.GetY(j))
vp.plot(yard, fill=False, hatch='x', color='black')
vp.draw()

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/amyniez/article/details/113572831