znlgis 博客

GIS开发与技术分享

第3章:几何对象模型

Shapely 实现了 OGC Simple Features 标准定义的完整几何类型体系。本章将深入介绍所有 8 种几何类型——Point、LineString、LinearRing、Polygon、MultiPoint、MultiLineString、MultiPolygon 和 GeometryCollection,以及 Shapely 2.0 中引入的不可变性、向量化创建等关键概念。


3.1 几何类型体系概述

3.1.1 OGC Simple Features 标准

Shapely 的几何模型遵循 OGC(Open Geospatial Consortium)Simple Features 规范。该规范定义了一套标准的几何类型及其操作,被广泛应用于 GIS 软件、空间数据库和地理数据格式中。

┌─────────────────────────────────────────────────────────────┐
│                  Shapely 几何类型继承体系                      │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│                    Geometry (基类)                           │
│                        │                                    │
│          ┌─────────────┼─────────────┐                     │
│          │             │             │                      │
│       0 维几何      1 维几何       2 维几何                   │
│          │             │             │                      │
│       Point       LineString     Polygon                   │
│          │        LinearRing                               │
│          │             │             │                      │
│     MultiPoint  MultiLineString  MultiPolygon              │
│          │             │             │                      │
│          └─────────────┼─────────────┘                     │
│                        │                                    │
│               GeometryCollection                           │
│              (异构几何集合)                                 │
│                                                             │
└─────────────────────────────────────────────────────────────┘

3.1.2 几何维度分类

维度 类型 说明 典型示例
0 维 Point, MultiPoint 点,没有长度和面积 城市位置、GPS 坐标
1 维 LineString, LinearRing, MultiLineString 线,有长度无面积 道路、河流、边界线
2 维 Polygon, MultiPolygon 面,有长度和面积 行政区域、湖泊、建筑物
混合 GeometryCollection 可包含任意维度的几何体 复合空间要素

3.1.3 基类 Geometry

所有 Shapely 几何对象都继承自 shapely.Geometry 基类:

from shapely import Point, LineString, Polygon, Geometry

p = Point(1, 2)
print(isinstance(p, Geometry))  # True

line = LineString([(0, 0), (1, 1)])
print(isinstance(line, Geometry))  # True

poly = Polygon([(0, 0), (1, 0), (1, 1), (0, 1)])
print(isinstance(poly, Geometry))  # True

3.2 Point(点)

3.2.1 基本概念

Point 是 0 维几何体,表示空间中的一个位置。点没有长度、面积或内部结构,仅有坐标值。

3.2.2 创建 Point

from shapely import Point

# 二维点
p1 = Point(1.0, 2.0)
print(p1)           # POINT (1 2)
print(p1.wkt)       # POINT (1 2)

# 三维点(Z 坐标)
p2 = Point(1.0, 2.0, 3.0)
print(p2)           # POINT Z (1 2 3)
print(p2.has_z)     # True

# 从元组创建
coords = (116.4, 39.9)
p3 = Point(coords)
print(p3)           # POINT (116.4 39.9)

# 从列表创建
p4 = Point([3.0, 4.0])
print(p4)           # POINT (3 4)

3.2.3 Point 属性

from shapely import Point

p = Point(3.0, 4.0, 5.0)

# 坐标访问
print(f"x = {p.x}")         # x = 3.0
print(f"y = {p.y}")         # y = 4.0
print(f"z = {p.z}")         # z = 5.0
print(f"has_z = {p.has_z}") # has_z = True

# 坐标序列
print(f"coords = {list(p.coords)}")  # coords = [(3.0, 4.0, 5.0)]

# 边界框
print(f"bounds = {p.bounds}")   # bounds = (3.0, 4.0, 3.0, 4.0)

# 0 维几何的度量
print(f"area = {p.area}")       # area = 0.0
print(f"length = {p.length}")   # length = 0.0

# 几何类型
print(f"geom_type = {p.geom_type}")  # geom_type = Point

3.2.4 空点

from shapely import Point

# 创建空点
empty_point = Point()
print(empty_point)           # POINT EMPTY
print(empty_point.is_empty)  # True
print(empty_point.bounds)    # (nan, nan, nan, nan)

# 空点没有坐标
print(list(empty_point.coords))  # []

3.3 LineString(线串)

3.3.1 基本概念

LineString 是 1 维几何体,由一系列有序坐标点按顺序连接而成的折线。LineString 至少需要 2 个坐标点。

3.3.2 创建 LineString

from shapely import LineString

# 从坐标列表创建
line1 = LineString([(0, 0), (1, 1), (2, 0)])
print(line1)  # LINESTRING (0 0, 1 1, 2 0)

# 从元组列表创建
coords = [(0, 0), (1, 2), (3, 1), (5, 4)]
line2 = LineString(coords)
print(f"线长度: {line2.length:.4f}")

# 从 Point 对象创建
from shapely import Point
p1, p2, p3 = Point(0, 0), Point(1, 1), Point(2, 0)
line3 = LineString([p1, p2, p3])
print(line3)  # LINESTRING (0 0, 1 1, 2 0)

# 三维线串
line_3d = LineString([(0, 0, 0), (1, 1, 1), (2, 0, 2)])
print(line_3d)       # LINESTRING Z (0 0 0, 1 1 1, 2 0 2)
print(line_3d.has_z)  # True

3.3.3 LineString 属性

from shapely import LineString

line = LineString([(0, 0), (3, 0), (3, 4)])

# 坐标序列
print(f"坐标: {list(line.coords)}")
# [(0.0, 0.0), (3.0, 0.0), (3.0, 4.0)]

# 长度
print(f"长度: {line.length}")  # 7.0 (3 + 4)

# 面积(线没有面积)
print(f"面积: {line.area}")    # 0.0

# 边界框
print(f"bounds: {line.bounds}")  # (0.0, 0.0, 3.0, 4.0)

# 端点
print(f"起点坐标: {line.coords[0]}")   # (0.0, 0.0)
print(f"终点坐标: {line.coords[-1]}")  # (3.0, 4.0)

# 是否闭合
print(f"is_closed: {line.is_closed}")  # False
print(f"is_ring: {line.is_ring}")      # False
print(f"is_simple: {line.is_simple}")  # True(不自交叉)

# 质心
print(f"质心: {line.centroid}")  # POINT (2.5714... 1.7142...)

3.3.4 空 LineString

from shapely import LineString

empty_line = LineString()
print(empty_line)           # LINESTRING EMPTY
print(empty_line.is_empty)  # True
print(empty_line.length)    # 0.0

3.4 LinearRing(线环)

3.4.1 基本概念

LinearRing 是闭合的 LineString,首尾坐标相同。LinearRing 是 Polygon 的边界组件,不常单独使用。至少需要 4 个坐标点(包括闭合点)。

3.4.2 创建 LinearRing

from shapely import LinearRing

# 显式闭合(首尾相同)
ring1 = LinearRing([(0, 0), (4, 0), (4, 3), (0, 3), (0, 0)])
print(ring1)  # LINEARRING (0 0, 4 0, 4 3, 0 3, 0 0)

# 自动闭合(Shapely 会自动添加闭合点)
ring2 = LinearRing([(0, 0), (4, 0), (4, 3), (0, 3)])
print(ring2)  # LINEARRING (0 0, 4 0, 4 3, 0 3, 0 0)

# 两种方式结果相同
print(ring1.equals(ring2))  # True

3.4.3 LinearRing 属性

from shapely import LinearRing

ring = LinearRing([(0, 0), (4, 0), (4, 3), (0, 3)])

# 坐标(包含闭合点)
print(f"坐标: {list(ring.coords)}")
# [(0.0, 0.0), (4.0, 0.0), (4.0, 3.0), (0.0, 3.0), (0.0, 0.0)]

# 周长
print(f"长度: {ring.length}")  # 14.0

# 闭合性
print(f"is_closed: {ring.is_closed}")  # True
print(f"is_ring: {ring.is_ring}")      # True

# 简单性(不自交叉)
print(f"is_simple: {ring.is_simple}")  # True

# 面积(LinearRing 没有面积,它只是边界线)
print(f"面积: {ring.area}")  # 0.0

3.4.4 线环方向

from shapely import LinearRing
import shapely

# 逆时针方向(正方向)
ccw_ring = LinearRing([(0, 0), (4, 0), (4, 3), (0, 3)])
print(f"逆时针: {shapely.is_ccw(ccw_ring)}")  # True

# 顺时针方向(负方向)
cw_ring = LinearRing([(0, 0), (0, 3), (4, 3), (4, 0)])
print(f"逆时针: {shapely.is_ccw(cw_ring)}")   # False

3.5 Polygon(多边形)

3.5.1 基本概念

Polygon 是 2 维几何体,由一个外环(exterior ring)和零个或多个内环(holes,即孔洞)组成。Polygon 有面积和周长。

3.5.2 创建简单 Polygon

from shapely import Polygon

# 从坐标列表创建(无孔洞)
poly1 = Polygon([(0, 0), (4, 0), (4, 3), (0, 3)])
print(poly1)
# POLYGON ((0 0, 4 0, 4 3, 0 3, 0 0))

# Shapely 会自动闭合多边形
print(f"面积: {poly1.area}")     # 12.0
print(f"周长: {poly1.length}")   # 14.0

# 从外环 LinearRing 创建
from shapely import LinearRing
exterior = LinearRing([(0, 0), (10, 0), (10, 10), (0, 10)])
poly2 = Polygon(exterior)
print(f"面积: {poly2.area}")  # 100.0

3.5.3 创建带孔洞的 Polygon

from shapely import Polygon

# 带一个孔洞的多边形
exterior = [(0, 0), (10, 0), (10, 10), (0, 10)]
hole1 = [(2, 2), (2, 4), (4, 4), (4, 2)]

poly_with_hole = Polygon(exterior, [hole1])
print(poly_with_hole)
print(f"面积: {poly_with_hole.area}")  # 100 - 4 = 96.0

# 带多个孔洞
hole2 = [(6, 6), (6, 8), (8, 8), (8, 6)]
poly_with_holes = Polygon(exterior, [hole1, hole2])
print(f"面积: {poly_with_holes.area}")  # 100 - 4 - 4 = 92.0
print(f"孔洞数: {len(list(poly_with_holes.interiors))}")  # 2

3.5.4 Polygon 属性

from shapely import Polygon

exterior = [(0, 0), (10, 0), (10, 10), (0, 10)]
hole = [(3, 3), (3, 7), (7, 7), (7, 3)]
poly = Polygon(exterior, [hole])

# 外环
print(f"外环: {poly.exterior}")
# LINEARRING (0 0, 10 0, 10 10, 0 10, 0 0)
print(f"外环类型: {type(poly.exterior)}")
# <class 'shapely.geometry.polygon.LinearRing'>

# 内环(孔洞)
for i, interior in enumerate(poly.interiors):
    print(f"内环 {i}: {interior}")
# 内环 0: LINEARRING (3 3, 3 7, 7 7, 7 3, 3 3)

# 面积和周长
print(f"面积: {poly.area}")     # 100 - 16 = 84.0
print(f"周长: {poly.length}")   # 40 + 16 = 56.0

# 边界框
print(f"bounds: {poly.bounds}")  # (0.0, 0.0, 10.0, 10.0)

# 质心
print(f"质心: {poly.centroid}")  # POINT (5 5)

# 有效性
print(f"is_valid: {poly.is_valid}")  # True

3.5.5 三角形多边形

from shapely import Polygon

# 三角形——最简单的多边形
triangle = Polygon([(0, 0), (4, 0), (2, 3)])
print(f"三角形面积: {triangle.area}")     # 6.0
print(f"三角形周长: {triangle.length:.4f}")  # 11.2111

3.6 MultiPoint(多点)

3.6.1 基本概念

MultiPoint 是点的集合,表示空间中的多个离散位置。

3.6.2 创建 MultiPoint

from shapely import MultiPoint, Point

# 从坐标列表创建
mp1 = MultiPoint([(0, 0), (1, 1), (2, 0)])
print(mp1)  # MULTIPOINT (0 0, 1 1, 2 0)

# 从 Point 对象创建
p1, p2, p3 = Point(0, 0), Point(1, 1), Point(2, 0)
mp2 = MultiPoint([p1, p2, p3])
print(mp2)

# 访问各点
print(f"点数量: {len(mp1.geoms)}")  # 3
for i, point in enumerate(mp1.geoms):
    print(f"  点 {i}: ({point.x}, {point.y})")

3.6.3 MultiPoint 属性

from shapely import MultiPoint

mp = MultiPoint([(0, 0), (3, 0), (3, 4), (0, 4)])

# 边界框
print(f"bounds: {mp.bounds}")  # (0.0, 0.0, 3.0, 4.0)

# 质心
print(f"质心: {mp.centroid}")  # POINT (1.5 2)

# 凸包
print(f"凸包: {mp.convex_hull}")
# POLYGON ((0 0, 0 4, 3 4, 3 0, 0 0))

# 迭代子几何
for geom in mp.geoms:
    print(f"  {geom.geom_type}: ({geom.x}, {geom.y})")

3.7 MultiLineString(多线串)

3.7.1 基本概念

MultiLineString 是线串的集合,表示多条不相连或相连的线段。

3.7.2 创建 MultiLineString

from shapely import MultiLineString, LineString

# 从坐标列表创建
mls1 = MultiLineString([
    [(0, 0), (1, 1), (2, 0)],
    [(3, 0), (4, 1), (5, 0)]
])
print(mls1)

# 从 LineString 对象创建
line1 = LineString([(0, 0), (1, 1)])
line2 = LineString([(2, 2), (3, 3)])
mls2 = MultiLineString([line1, line2])
print(mls2)

# 访问各线
print(f"线数量: {len(mls1.geoms)}")  # 2
for i, line in enumerate(mls1.geoms):
    print(f"  线 {i}: 长度={line.length:.4f}")

3.7.3 MultiLineString 属性

from shapely import MultiLineString

mls = MultiLineString([
    [(0, 0), (5, 0)],
    [(0, 1), (5, 1)],
    [(0, 2), (5, 2)]
])

# 总长度
print(f"总长度: {mls.length}")  # 15.0

# 边界框
print(f"bounds: {mls.bounds}")  # (0.0, 0.0, 5.0, 2.0)

# 质心
print(f"质心: {mls.centroid}")

# 各组成线段
for i, geom in enumerate(mls.geoms):
    print(f"  线 {i}: {geom.wkt}")

3.8 MultiPolygon(多边形集合)

3.8.1 基本概念

MultiPolygon 是多边形的集合。集合中的多边形不能重叠(可以相邻或分离)。

3.8.2 创建 MultiPolygon

from shapely import MultiPolygon, Polygon

# 从 Polygon 对象创建
poly1 = Polygon([(0, 0), (2, 0), (2, 2), (0, 2)])
poly2 = Polygon([(3, 3), (5, 3), (5, 5), (3, 5)])
mp = MultiPolygon([poly1, poly2])
print(mp)

# 从坐标列表创建(每个元素是 (exterior, [holes]) 元组)
mp2 = MultiPolygon([
    ([(0, 0), (2, 0), (2, 2), (0, 2)], []),           # 无孔洞
    ([(3, 0), (5, 0), (5, 2), (3, 2)], [              # 有孔洞
        [(3.5, 0.5), (3.5, 1.5), (4.5, 1.5), (4.5, 0.5)]
    ])
])
print(f"面积: {mp2.area}")

3.8.3 MultiPolygon 属性

from shapely import MultiPolygon, Polygon

poly1 = Polygon([(0, 0), (4, 0), (4, 3), (0, 3)])
poly2 = Polygon([(5, 0), (9, 0), (9, 3), (5, 3)])
mp = MultiPolygon([poly1, poly2])

# 总面积
print(f"总面积: {mp.area}")     # 24.0

# 总周长
print(f"总周长: {mp.length}")   # 28.0

# 多边形数量
print(f"数量: {len(mp.geoms)}")  # 2

# 边界框
print(f"bounds: {mp.bounds}")  # (0.0, 0.0, 9.0, 3.0)

# 迭代各多边形
for i, poly in enumerate(mp.geoms):
    print(f"  多边形 {i}: 面积={poly.area}, 周长={poly.length}")

3.9 GeometryCollection(几何集合)

3.9.1 基本概念

GeometryCollection 是异构几何集合,可以包含任意类型和维度的几何体。

3.9.2 创建 GeometryCollection

from shapely import GeometryCollection, Point, LineString, Polygon

# 创建异构集合
gc = GeometryCollection([
    Point(1, 2),
    LineString([(0, 0), (3, 3)]),
    Polygon([(5, 5), (8, 5), (8, 8), (5, 8)])
])
print(gc)
print(f"几何体数量: {len(gc.geoms)}")  # 3

# 遍历并判断类型
for geom in gc.geoms:
    print(f"  类型: {geom.geom_type}, WKT: {geom.wkt}")

3.9.3 GeometryCollection 属性

from shapely import GeometryCollection, Point, LineString, Polygon

gc = GeometryCollection([
    Point(0, 0),
    LineString([(1, 0), (1, 5)]),
    Polygon([(2, 0), (4, 0), (4, 3), (2, 3)])
])

# 总面积(只计算面状几何)
print(f"总面积: {gc.area}")     # 6.0

# 总长度(线 + 面周长)
print(f"总长度: {gc.length}")   # 5.0 + 10.0 = 15.0

# 边界框
print(f"bounds: {gc.bounds}")  # (0.0, 0.0, 4.0, 5.0)

# 空集合
empty_gc = GeometryCollection()
print(f"空集合: {empty_gc}")           # GEOMETRYCOLLECTION EMPTY
print(f"是否为空: {empty_gc.is_empty}")  # True

3.10 几何对象的不可变性(Shapely 2.0+)

3.10.1 不可变性概述

从 Shapely 2.0 开始,所有几何对象都是不可变的(immutable)。这是 2.0 版本最重要的架构变化之一。

from shapely import Point

p = Point(1, 2)

# 不能修改几何体的坐标
try:
    p.coords = [(3, 4)]
except AttributeError as e:
    print(f"不可变: {e}")
# AttributeError: attribute 'coords' of 'Point' objects is not writable

# 正确做法:创建新的几何体
p_new = Point(3, 4)

3.10.2 可哈希性

由于不可变,Shapely 2.0 的几何对象是可哈希的(hashable)

from shapely import Point, Polygon

p1 = Point(1, 2)
p2 = Point(3, 4)
p3 = Point(1, 2)  # 与 p1 坐标相同

# 可用作集合元素
point_set = {p1, p2, p3}
print(f"集合大小: {len(point_set)}")  # 可能是 2 或 3
# 注意:哈希基于对象标识,不是基于坐标值

# 可用作字典键
point_dict = {p1: "位置A", p2: "位置B"}
print(point_dict[p1])  # "位置A"

3.10.3 不可变性的好处

  • 线程安全:不可变对象天然线程安全
  • 可哈希:可以用作字典键和集合元素
  • 可预测:没有意外的状态改变
  • 性能优化:允许更多的内部缓存

3.11 空几何体

3.11.1 各类型的空几何体

每种几何类型都可以创建空实例:

from shapely import (
    Point, LineString, LinearRing, Polygon,
    MultiPoint, MultiLineString, MultiPolygon,
    GeometryCollection
)

# 所有类型的空几何体
empty_geoms = {
    'Point': Point(),
    'LineString': LineString(),
    'LinearRing': LinearRing(),
    'Polygon': Polygon(),
    'MultiPoint': MultiPoint(),
    'MultiLineString': MultiLineString(),
    'MultiPolygon': MultiPolygon(),
    'GeometryCollection': GeometryCollection(),
}

for name, geom in empty_geoms.items():
    print(f"{name:25s} is_empty={geom.is_empty}  WKT={geom.wkt}")

# 输出:
# Point                     is_empty=True  WKT=POINT EMPTY
# LineString                is_empty=True  WKT=LINESTRING EMPTY
# LinearRing                is_empty=True  WKT=LINEARRING EMPTY
# Polygon                   is_empty=True  WKT=POLYGON EMPTY
# MultiPoint                is_empty=True  WKT=MULTIPOINT EMPTY
# MultiLineString           is_empty=True  WKT=MULTILINESTRING EMPTY
# MultiPolygon              is_empty=True  WKT=MULTIPOLYGON EMPTY
# GeometryCollection        is_empty=True  WKT=GEOMETRYCOLLECTION EMPTY

3.11.2 空几何体的特性

from shapely import Point, Polygon

empty_point = Point()
empty_poly = Polygon()

# 空几何体的度量
print(f"空点面积: {empty_point.area}")     # 0.0
print(f"空面面积: {empty_poly.area}")      # 0.0
print(f"空面周长: {empty_poly.length}")    # 0.0

# 空几何体的边界
print(f"空点 bounds: {empty_point.bounds}")
# (nan, nan, nan, nan)

# 空几何体是有效的
print(f"空点有效: {empty_point.is_valid}")  # True

# 空几何体的空间关系
p = Point(1, 2)
print(f"空点与点相交: {empty_point.intersects(p)}")  # False
print(f"空点与点不相交: {empty_point.disjoint(p)}")  # True

3.12 向量化创建(shapely 模块级函数)

3.12.1 批量创建几何体

Shapely 2.0 提供了模块级函数,支持使用 NumPy 数组批量创建几何体,性能远优于循环创建。

import numpy as np
import shapely

# 批量创建点
x = np.array([0, 1, 2, 3, 4])
y = np.array([0, 1, 0, 1, 0])
points = shapely.points(x, y)
print(f"类型: {type(points)}")     # <class 'numpy.ndarray'>
print(f"数量: {len(points)}")       # 5
print(f"第一个: {points[0]}")      # POINT (0 0)
print(f"元素类型: {points.dtype}")  # object (Shapely 几何对象)

3.12.2 批量创建线串

import numpy as np
import shapely

# 批量创建线串——每条线由坐标数组定义
coords = np.array([
    [[0, 0], [1, 1], [2, 0]],
    [[3, 0], [4, 1], [5, 0]],
    [[6, 0], [7, 1], [8, 0]],
])
lines = shapely.linestrings(coords)
print(f"线数量: {len(lines)}")
for line in lines:
    print(f"  {line.wkt}")

3.12.3 批量创建多边形

import numpy as np
import shapely

# 批量创建矩形多边形
rings = np.array([
    [[0, 0], [2, 0], [2, 2], [0, 2], [0, 0]],
    [[3, 0], [5, 0], [5, 2], [3, 2], [3, 0]],
    [[6, 0], [8, 0], [8, 2], [6, 2], [6, 0]],
])
polygons = shapely.polygons(rings)
print(f"多边形数量: {len(polygons)}")
for poly in polygons:
    print(f"  面积: {poly.area}")

# 所有面积为 4.0

3.12.4 性能对比

import numpy as np
import shapely
from shapely import Point
import time

n = 100000

# 方式 1:循环创建(慢)
start = time.time()
points_loop = [Point(i, i) for i in range(n)]
t_loop = time.time() - start

# 方式 2:向量化创建(快)
start = time.time()
x = np.arange(n, dtype=float)
points_vec = shapely.points(x, x)
t_vec = time.time() - start

print(f"循环创建 {n} 个点: {t_loop:.3f} 秒")
print(f"向量化创建 {n} 个点: {t_vec:.3f} 秒")
print(f"加速比: {t_loop / t_vec:.1f}x")
# 向量化通常快 10-50 倍

3.13 box() 快捷函数

3.13.1 创建矩形

shapely.box() 是创建轴对齐矩形的快捷函数:

import shapely

# box(xmin, ymin, xmax, ymax)
rect = shapely.box(0, 0, 4, 3)
print(rect)
# POLYGON ((4 0, 4 3, 0 3, 0 0, 4 0))
print(f"面积: {rect.area}")   # 12.0
print(f"周长: {rect.length}")  # 14.0

3.13.2 批量创建矩形

import numpy as np
import shapely

# 批量创建矩形
xmin = np.array([0, 5, 10])
ymin = np.array([0, 0, 0])
xmax = np.array([3, 8, 13])
ymax = np.array([2, 2, 2])

rects = shapely.box(xmin, ymin, xmax, ymax)
print(f"矩形数量: {len(rects)}")
for r in rects:
    print(f"  面积: {r.area}, bounds: {r.bounds}")

# 面积: 6.0, bounds: (0.0, 0.0, 3.0, 2.0)
# 面积: 6.0, bounds: (5.0, 0.0, 8.0, 2.0)
# 面积: 6.0, bounds: (10.0, 0.0, 13.0, 2.0)

3.14 几何类型判断

3.14.1 使用 geom_type 属性

from shapely import Point, LineString, Polygon, MultiPoint
from shapely import GeometryCollection

geoms = [
    Point(0, 0),
    LineString([(0, 0), (1, 1)]),
    Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]),
    MultiPoint([(0, 0), (1, 1)]),
    GeometryCollection([Point(0, 0)]),
]

for geom in geoms:
    print(f"geom_type: {geom.geom_type:25s} WKT: {geom.wkt}")

# geom_type: Point                     WKT: POINT (0 0)
# geom_type: LineString                WKT: LINESTRING (0 0, 1 1)
# geom_type: Polygon                   WKT: POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))
# geom_type: MultiPoint                WKT: MULTIPOINT (0 0, 1 1)
# geom_type: GeometryCollection        WKT: GEOMETRYCOLLECTION (POINT (0 0))

3.14.2 使用 shapely.get_type_id()

import shapely
from shapely import Point, LineString, Polygon

# 几何类型 ID
type_names = {
    0: 'Point', 1: 'LineString', 2: 'LinearRing',
    3: 'Polygon', 4: 'MultiPoint', 5: 'MultiLineString',
    6: 'MultiPolygon', 7: 'GeometryCollection'
}

geoms = [Point(0, 0), LineString([(0, 0), (1, 1)]), Polygon([(0, 0), (1, 0), (1, 1)])]

type_ids = shapely.get_type_id(geoms)
for geom, tid in zip(geoms, type_ids):
    print(f"type_id={tid}, type_name={type_names[tid]}")

3.14.3 使用 isinstance 判断

from shapely import Point, LineString, Polygon, MultiPoint
from shapely import Geometry

p = Point(1, 2)

# isinstance 判断
print(isinstance(p, Point))      # True
print(isinstance(p, Geometry))   # True
print(isinstance(p, Polygon))    # False

# 用于过滤
geoms = [Point(0, 0), LineString([(0, 0), (1, 1)]), Polygon([(0, 0), (1, 0), (1, 1)])]
points_only = [g for g in geoms if isinstance(g, Point)]
print(f"仅点: {len(points_only)} 个")  # 1 个

3.15 本章小结

本章我们学习了 Shapely 的完整几何类型体系:

几何类型 维度 最少坐标点 关键特性
Point 0 维 1 单个位置点
LineString 1 维 2 有序折线
LinearRing 1 维 4 闭合折线,Polygon 的组件
Polygon 2 维 4 外环 + 可选内环(孔洞)
MultiPoint 0 维 1+ 点集合
MultiLineString 1 维 2+ 线集合
MultiPolygon 2 维 4+ 多边形集合(不重叠)
GeometryCollection 混合 任意 异构集合

关键概念:

  • 不可变性:Shapely 2.0 中几何对象不可变、可哈希
  • 向量化创建:使用 shapely.points()shapely.polygons() 等函数批量创建
  • box() 快捷函数:快速创建轴对齐矩形
  • 空几何体:每种类型都可创建空实例

下一章我们将深入学习几何对象的属性与方法。