znlgis 博客

GIS开发与技术分享

第13章:序列化与反序列化(WKT/WKB/GeoJSON)

几何体的序列化与反序列化是 GIS 数据交换的基础。无论是存储到数据库、通过网络传输,还是在不同系统间共享数据,都需要将内存中的几何对象转换为标准格式。Shapely 支持 WKT(Well-Known Text)、WKB(Well-Known Binary)、GeoJSON 以及 Pickle 等多种序列化格式,本章将全面介绍这些格式的使用方法、参数选项和性能特点。


WKT(Well-Known Text)

WKT 格式概述

WKT 是 OGC(开放地理空间联盟)定义的文本格式,可读性好,常用于调试和数据展示。

from shapely import Point, LineString, Polygon

# 各种几何类型的 WKT 表示
print(Point(1, 2).wkt)
# POINT (1 2)

print(Point(1, 2, 3).wkt)
# POINT Z (1 2 3)

print(LineString([(0, 0), (1, 1), (2, 0)]).wkt)
# LINESTRING (0 0, 1 1, 2 0)

print(Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]).wkt)
# POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))

to_wkt 函数

from shapely import to_wkt, Point, LineString, Polygon

# 基本用法
point = Point(1.123456789, 2.987654321)
print(to_wkt(point))
# POINT (1.123456789 2.987654321)

# rounding_precision:控制小数位数
print(to_wkt(point, rounding_precision=3))
# POINT (1.123 2.988)

print(to_wkt(point, rounding_precision=0))
# POINT (1 3)

# trim:去除尾部多余的零
print(to_wkt(Point(1.0, 2.0), rounding_precision=6, trim=True))
# POINT (1 2)

print(to_wkt(Point(1.0, 2.0), rounding_precision=6, trim=False))
# POINT (1.000000 2.000000)

output_dimension 参数

from shapely import to_wkt, Point

# 3D 点
point_3d = Point(1, 2, 3)

# 输出 3D
print(to_wkt(point_3d, output_dimension=3))
# POINT Z (1 2 3)

# 强制输出 2D(丢弃 Z 坐标)
print(to_wkt(point_3d, output_dimension=2))
# POINT (1 2)

from_wkt 函数

from shapely import from_wkt

# 基本解析
point = from_wkt("POINT (1 2)")
print(f"类型: {point.geom_type}, 坐标: ({point.x}, {point.y})")

line = from_wkt("LINESTRING (0 0, 1 1, 2 0)")
print(f"类型: {line.geom_type}, 顶点数: {len(line.coords)}")

polygon = from_wkt("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))")
print(f"类型: {polygon.geom_type}, 面积: {polygon.area}")

# 解析 3D 几何
point_3d = from_wkt("POINT Z (1 2 3)")
print(f"Z 坐标: {point_3d.z}")

on_invalid 参数

from shapely import from_wkt
import warnings

# 有效的 WKT
valid = from_wkt("POINT (1 2)")
print(f"有效: {valid}")

# 无效的 WKT 字符串

# on_invalid='raise'(默认)- 抛出异常
try:
    from_wkt("INVALID WKT STRING", on_invalid='raise')
except Exception as e:
    print(f"异常: {type(e).__name__}: {e}")

# on_invalid='warn' - 发出警告,返回 None
with warnings.catch_warnings(record=True) as w:
    warnings.simplefilter("always")
    result = from_wkt("INVALID WKT STRING", on_invalid='warn')
    print(f"警告模式返回: {result}")
    if w:
        print(f"警告: {w[0].message}")

# on_invalid='ignore' - 静默返回 None
result = from_wkt("INVALID WKT STRING", on_invalid='ignore')
print(f"忽略模式返回: {result}")

.wkt 属性快捷方式

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

# 所有几何类型的 WKT 表示
geometries = [
    Point(0, 0),
    LineString([(0, 0), (1, 1)]),
    Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]),
    MultiPoint([(0, 0), (1, 1)]),
    MultiLineString([[(0, 0), (1, 0)], [(1, 1), (2, 2)]]),
    MultiPolygon([
        ([(0, 0), (1, 0), (1, 1), (0, 1)], []),
        ([(2, 2), (3, 2), (3, 3), (2, 3)], [])
    ]),
    GeometryCollection([Point(0, 0), LineString([(1, 1), (2, 2)])]),
]

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

批量处理 WKT

from shapely import to_wkt, from_wkt
import numpy as np

# 批量序列化
from shapely import Point
points = np.array([Point(i, i*2) for i in range(5)])
wkt_array = to_wkt(points)
print(f"批量序列化结果类型: {type(wkt_array)}")
for w in wkt_array:
    print(f"  {w}")

# 批量反序列化
wkt_strings = np.array([
    "POINT (0 0)",
    "POINT (1 2)",
    "POINT (3 4)",
])
geoms = from_wkt(wkt_strings)
print(f"\n批量反序列化:")
for g in geoms:
    print(f"  {g}")

WKB(Well-Known Binary)

WKB 格式概述

WKB 是几何体的二进制表示格式,体积小、解析快,适合存储和网络传输。

from shapely import Point

point = Point(1, 2)

# WKB 二进制
wkb_bytes = point.wkb
print(f"WKB 字节: {wkb_bytes}")
print(f"WKB 长度: {len(wkb_bytes)} 字节")

# WKB 十六进制
wkb_hex = point.wkb_hex
print(f"WKB Hex: {wkb_hex}")

to_wkb 函数

from shapely import to_wkb, Point, Polygon

point = Point(1.5, 2.5)

# 默认 WKB(小端序、二进制)
wkb = to_wkb(point)
print(f"默认 WKB: {wkb.hex()}")

# 十六进制输出
wkb_hex = to_wkb(point, hex=True)
print(f"Hex WKB: {wkb_hex}")

# 字节序控制
# byte_order=0: 大端序(Big-Endian / XDR)
# byte_order=1: 小端序(Little-Endian / NDR)
wkb_be = to_wkb(point, byte_order=0)
wkb_le = to_wkb(point, byte_order=1)
print(f"大端序第1字节: {wkb_be[0]:02x}")  # 00
print(f"小端序第1字节: {wkb_le[0]:02x}")  # 01

output_dimension 参数

from shapely import to_wkb, Point

point_3d = Point(1, 2, 3)

# 3D WKB
wkb_3d = to_wkb(point_3d, output_dimension=3, hex=True)
print(f"3D WKB: {wkb_3d}")

# 强制 2D
wkb_2d = to_wkb(point_3d, output_dimension=2, hex=True)
print(f"2D WKB: {wkb_2d}")

print(f"3D 长度: {len(wkb_3d)} 字符")
print(f"2D 长度: {len(wkb_2d)} 字符")

SRID 嵌入

from shapely import to_wkb, from_wkb, Point
from shapely import geos_version

point = Point(116.4, 39.9)

# 嵌入 SRID(Extended WKB / EWKB)
ewkb = to_wkb(point, include_srid=True, hex=True)
print(f"带 SRID 的 WKB: {ewkb}")

# 注意:Shapely 本身不跟踪 SRID
# 但可以通过 EWKB 与 PostGIS 等数据库交互

from_wkb 函数

from shapely import from_wkb, to_wkb, Point, Polygon

# 从二进制 WKB 还原
point = Point(3.14, 2.72)
wkb = to_wkb(point)
restored = from_wkb(wkb)
print(f"还原: {restored}")
print(f"坐标: ({restored.x}, {restored.y})")

# 从十六进制 WKB 还原
wkb_hex = to_wkb(point, hex=True)
restored_hex = from_wkb(wkb_hex)
print(f"从 Hex 还原: {restored_hex}")

# on_invalid 参数同样适用
result = from_wkb(b'\x00\x00', on_invalid='ignore')
print(f"无效 WKB: {result}")  # None

.wkb_hex 属性

from shapely import Point, LineString, Polygon

# 各种类型的 WKB Hex
geoms = [
    Point(1, 2),
    LineString([(0, 0), (1, 1)]),
    Polygon([(0, 0), (1, 0), (1, 1), (0, 0)]),
]

for geom in geoms:
    hex_str = geom.wkb_hex
    print(f"{geom.geom_type:15s}: {hex_str[:40]}... ({len(hex_str)} 字符)")

批量 WKB 操作

from shapely import to_wkb, from_wkb, Point
import numpy as np

# 批量序列化
points = np.array([Point(i, i*2) for i in range(5)])
wkb_array = to_wkb(points)
print(f"批量 WKB 类型: {type(wkb_array)}")

# 批量反序列化
restored = from_wkb(wkb_array)
for r in restored:
    print(f"  {r}")

# 十六进制批量
hex_array = to_wkb(points, hex=True)
for h in hex_array:
    print(f"  {h}")

GeoJSON

GeoJSON 格式概述

GeoJSON 是基于 JSON 的地理数据格式,广泛用于 Web GIS 应用。

from shapely import Point
from shapely.geometry import mapping, shape
import json

point = Point(116.4, 39.9)

# 使用 mapping() 转换为 dict
geojson_dict = mapping(point)
print(json.dumps(geojson_dict, indent=2))
# {
#   "type": "Point",
#   "coordinates": [116.4, 39.9]
# }

to_geojson 函数

from shapely import to_geojson, Point, LineString, Polygon

# 基本转换
point = Point(116.4, 39.9)
geojson_str = to_geojson(point)
print(f"GeoJSON: {geojson_str}")

# 带缩进的格式化输出
line = LineString([(0, 0), (1, 1), (2, 0)])
formatted = to_geojson(line, indent=2)
print(f"格式化 GeoJSON:\n{formatted}")

# 多边形
polygon = Polygon([(0, 0), (1, 0), (1, 1), (0, 1)])
print(to_geojson(polygon, indent=2))

mapping() 函数

from shapely.geometry import mapping
from shapely import (
    Point, LineString, Polygon,
    MultiPoint, MultiLineString, MultiPolygon
)

# mapping() 返回 Python 字典,符合 GeoJSON 规范
geoms = {
    "点": Point(1, 2),
    "线": LineString([(0, 0), (1, 1)]),
    "面": Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]),
    "多点": MultiPoint([(0, 0), (1, 1)]),
    "多线": MultiLineString([[(0, 0), (1, 0)], [(1, 1), (2, 2)]]),
}

for name, geom in geoms.items():
    d = mapping(geom)
    print(f"{name}: type={d['type']}, "
          f"coordinates 类型={type(d['coordinates']).__name__}")

shape() 函数

from shapely.geometry import shape, mapping

# 从 GeoJSON dict 创建几何体
geojson_point = {
    "type": "Point",
    "coordinates": [116.4, 39.9]
}
point = shape(geojson_point)
print(f"Point: {point}")

geojson_polygon = {
    "type": "Polygon",
    "coordinates": [
        [[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]]
    ]
}
polygon = shape(geojson_polygon)
print(f"Polygon: {polygon}")
print(f"面积: {polygon.area}")

# 带孔洞的多边形
geojson_with_hole = {
    "type": "Polygon",
    "coordinates": [
        [[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]],  # 外环
        [[2, 2], [2, 8], [8, 8], [8, 2], [2, 2]]        # 孔洞
    ]
}
poly_with_hole = shape(geojson_with_hole)
print(f"带孔洞面积: {poly_with_hole.area}")

geo_interface 协议

from shapely import Point, Polygon
from shapely.geometry import shape

# Shapely 几何体实现了 __geo_interface__ 协议
point = Point(1, 2)
print(f"__geo_interface__: {point.__geo_interface__}")
# {'type': 'Point', 'coordinates': (1.0, 2.0)}

# 任何实现了 __geo_interface__ 的对象都可以用 shape() 转换
class MyGeometry:
    @property
    def __geo_interface__(self):
        return {
            'type': 'Point',
            'coordinates': (3.0, 4.0)
        }

my_geom = MyGeometry()
shapely_geom = shape(my_geom)
print(f"自定义对象转换: {shapely_geom}")

GeoJSON 规范要求

from shapely import Point, Polygon
from shapely.geometry import mapping
import json

# GeoJSON 规范要求使用 WGS84 坐标系 (EPSG:4326)
# 经度在前,纬度在后
beijing = Point(116.4, 39.9)  # (经度, 纬度)

geojson = mapping(beijing)
print(json.dumps(geojson))
# {"type": "Point", "coordinates": [116.4, 39.9]}

# 右手规则:外环逆时针,孔洞顺时针
# Shapely 的 Polygon 可能不遵循此规则
# 使用 orient() 可以规范化方向
from shapely.geometry import polygon as poly_module
from shapely import Polygon

exterior = [(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)]  # 顺时针
hole = [(2, 2), (8, 2), (8, 8), (2, 8), (2, 2)]           # 逆时针

poly = Polygon(exterior, [hole])
oriented = poly_module.orient(poly, sign=1.0)  # 确保右手规则
print(f"外环方向修正后: {oriented.wkt[:60]}...")

构造 FeatureCollection

from shapely import Point, Polygon
from shapely.geometry import mapping
import json

# 虽然 Shapely 不直接支持 Feature/FeatureCollection
# 但可以手动构造
features = []

# 添加点要素
for i in range(3):
    feature = {
        "type": "Feature",
        "geometry": mapping(Point(i, i)),
        "properties": {
            "name": f"Point_{i}",
            "value": i * 10
        }
    }
    features.append(feature)

# 构造 FeatureCollection
feature_collection = {
    "type": "FeatureCollection",
    "features": features
}

print(json.dumps(feature_collection, indent=2))

Pickle 序列化

基本 Pickle 操作

import pickle
from shapely import Point, LineString, Polygon

# 序列化
point = Point(1, 2)
pickled = pickle.dumps(point)
print(f"Pickle 大小: {len(pickled)} 字节")

# 反序列化
restored = pickle.loads(pickled)
print(f"还原: {restored}")
print(f"相等: {point.equals(restored)}")

多种几何体的 Pickle

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

geometries = [
    Point(1, 2),
    LineString([(0, 0), (1, 1), (2, 0)]),
    Polygon([(0, 0), (10, 0), (10, 10), (0, 10)]),
    MultiPoint([(0, 0), (1, 1), (2, 2)]),
]

# 序列化整个列表
data = pickle.dumps(geometries)
print(f"列表 Pickle 大小: {len(data)} 字节")

# 反序列化
restored = pickle.loads(data)
for orig, rest in zip(geometries, restored):
    print(f"{orig.geom_type}: 相等={orig.equals(rest)}")

在多进程中传递几何体

from shapely import Point, Polygon
import pickle

# 模拟多进程数据传递
# 主进程:创建几何体并序列化
polygon = Polygon([(0, 0), (10, 0), (10, 10), (0, 10)])
serialized = pickle.dumps(polygon)

# 子进程:反序列化并处理
def worker_process(data):
    """模拟子进程的工作函数"""
    geom = pickle.loads(data)
    area = geom.area
    centroid = geom.centroid
    return {
        'area': area,
        'centroid': (centroid.x, centroid.y)
    }

result = worker_process(serialized)
print(f"面积: {result['area']}")
print(f"质心: {result['centroid']}")

# 使用 concurrent.futures 的实际示例
from concurrent.futures import ProcessPoolExecutor

def compute_area(wkb):
    """在子进程中计算面积"""
    from shapely import from_wkb
    geom = from_wkb(wkb)
    return geom.area

# 准备数据(使用 WKB 比 Pickle 更通用)
from shapely import to_wkb, box
polygons_wkb = [to_wkb(box(i, i, i+5, i+5)) for i in range(5)]

# 注意:在实际使用中取消下面的注释
# with ProcessPoolExecutor(max_workers=2) as executor:
#     areas = list(executor.map(compute_area, polygons_wkb))
#     print(f"面积列表: {areas}")

格式化输出

f-string 格式化

from shapely import Point, LineString

point = Point(1.123456789, 2.987654321)

# 控制小数位数(需要 Shapely 2.0+)
# 标准的 .wkt 属性
print(f"默认 WKT: {point.wkt}")

# 使用 to_wkt 控制精度
from shapely import to_wkt
print(f"3位精度: {to_wkt(point, rounding_precision=3)}")
print(f"6位精度: {to_wkt(point, rounding_precision=6)}")

# WKB 十六进制
from shapely import to_wkb
hex_wkb = to_wkb(point, hex=True)
print(f"WKB Hex: {hex_wkb}")

自定义格式化函数

from shapely import Point, LineString, to_wkt

def format_geometry(geom, precision=3, max_length=80):
    """自定义几何体格式化"""
    wkt = to_wkt(geom, rounding_precision=precision, trim=True)
    if len(wkt) > max_length:
        return wkt[:max_length-3] + "..."
    return wkt

# 使用
line = LineString([(i*0.1, i*0.2) for i in range(20)])
print(format_geometry(line, precision=2))
print(format_geometry(line, precision=2, max_length=50))

批量序列化与反序列化

处理几何数组

from shapely import (
    to_wkt, from_wkt, to_wkb, from_wkb, to_geojson,
    Point, LineString, box
)
import numpy as np

# 创建几何数组
geoms = np.array([Point(i, i*2) for i in range(5)])

# 批量转 WKT
wkt_array = to_wkt(geoms, rounding_precision=2)
print("WKT 数组:")
for w in wkt_array:
    print(f"  {w}")

# 批量转 WKB(十六进制)
wkb_array = to_wkb(geoms, hex=True)
print("\nWKB Hex 数组:")
for w in wkb_array:
    print(f"  {w}")

# 批量反序列化
restored_from_wkt = from_wkt(wkt_array)
restored_from_wkb = from_wkb(wkb_array)

print("\n从 WKT 还原:")
for g in restored_from_wkt:
    print(f"  {g}")

处理 None 和无效值

from shapely import to_wkt, from_wkt, Point
import numpy as np

# 包含 None 的数组
geoms = np.array([Point(1, 1), None, Point(3, 3)], dtype=object)

# to_wkt 处理 None
wkt_result = to_wkt(geoms)
print(f"含 None 的 WKT: {wkt_result}")

# from_wkt 处理无效字符串
wkt_strings = np.array([
    "POINT (1 1)",
    "INVALID",
    "POINT (3 3)"
])
result = from_wkt(wkt_strings, on_invalid='ignore')
print(f"含无效值的结果: {result}")

性能比较

WKT vs WKB vs GeoJSON 速度对比

from shapely import (
    to_wkt, from_wkt, to_wkb, from_wkb, to_geojson,
    Point, Polygon, box
)
from shapely.geometry import mapping, shape
import time
import json

# 创建测试几何体
polygon = Polygon([
    (i * 0.1, (i * 0.1) ** 2 % 10)
    for i in range(100)
])

n_iterations = 1000

# WKT 序列化/反序列化
start = time.perf_counter()
for _ in range(n_iterations):
    wkt = to_wkt(polygon)
wkt_ser_time = time.perf_counter() - start

start = time.perf_counter()
for _ in range(n_iterations):
    from_wkt(wkt)
wkt_deser_time = time.perf_counter() - start

# WKB 序列化/反序列化
start = time.perf_counter()
for _ in range(n_iterations):
    wkb = to_wkb(polygon)
wkb_ser_time = time.perf_counter() - start

start = time.perf_counter()
for _ in range(n_iterations):
    from_wkb(wkb)
wkb_deser_time = time.perf_counter() - start

# GeoJSON 序列化/反序列化
start = time.perf_counter()
for _ in range(n_iterations):
    gj = to_geojson(polygon)
gj_ser_time = time.perf_counter() - start

start = time.perf_counter()
for _ in range(n_iterations):
    shape(json.loads(gj))
gj_deser_time = time.perf_counter() - start

print(f"{'格式':<12} {'序列化(ms)':<14} {'反序列化(ms)':<14} {'大小(bytes)'}")
print("-" * 55)
print(f"{'WKT':<12} {wkt_ser_time*1000:<14.2f} {wkt_deser_time*1000:<14.2f} {len(wkt)}")
print(f"{'WKB':<12} {wkb_ser_time*1000:<14.2f} {wkb_deser_time*1000:<14.2f} {len(wkb)}")
print(f"{'GeoJSON':<12} {gj_ser_time*1000:<14.2f} {gj_deser_time*1000:<14.2f} {len(gj)}")

大小对比

from shapely import to_wkt, to_wkb, to_geojson, Point, LineString, Polygon

test_cases = [
    ("简单点", Point(116.123456, 39.654321)),
    ("简单线", LineString([(i, i*2) for i in range(10)])),
    ("简单面", Polygon([(i*10, (i*10)**2 % 100) for i in range(20)])),
]

print(f"{'几何类型':<12} {'WKT(字节)':<14} {'WKB(字节)':<14} {'GeoJSON(字节)'}")
print("-" * 55)
for name, geom in test_cases:
    wkt_size = len(to_wkt(geom).encode('utf-8'))
    wkb_size = len(to_wkb(geom))
    gj_size = len(to_geojson(geom).encode('utf-8'))
    print(f"{name:<12} {wkt_size:<14} {wkb_size:<14} {gj_size}")

与数据库交互

PostGIS WKB 格式

from shapely import to_wkb, from_wkb, Point

# PostGIS 使用 EWKB(Extended WKB)格式
# 包含 SRID 信息

point = Point(116.4, 39.9)

# 生成 EWKB Hex(适合 PostGIS)
ewkb_hex = to_wkb(point, hex=True, include_srid=True)
print(f"EWKB Hex: {ewkb_hex}")

# 常规 WKB Hex
wkb_hex = to_wkb(point, hex=True)
print(f"WKB Hex:  {wkb_hex}")

# 模拟从 PostGIS 读取
# 假设从数据库获得 WKB Hex 字符串
db_wkb_hex = wkb_hex
geom = from_wkb(db_wkb_hex)
print(f"从数据库还原: {geom}")

模拟数据库交互

from shapely import to_wkb, from_wkb, Point, Polygon
import json

# 模拟空间数据的存储与读取
class SpatialDatabase:
    """简单的空间数据存储模拟"""

    def __init__(self):
        self.records = []

    def insert(self, name, geometry):
        """存储几何体(使用 WKB)"""
        wkb = to_wkb(geometry, hex=True)
        self.records.append({
            'name': name,
            'geom_wkb': wkb
        })

    def query_all(self):
        """读取所有记录"""
        results = []
        for record in self.records:
            geom = from_wkb(record['geom_wkb'])
            results.append({
                'name': record['name'],
                'geometry': geom
            })
        return results

# 使用
db = SpatialDatabase()
db.insert("北京", Point(116.4, 39.9))
db.insert("上海", Point(121.5, 31.2))
db.insert("广州", Point(113.3, 23.1))

# 查询
records = db.query_all()
for r in records:
    print(f"{r['name']}: {r['geometry']}")

与 SQLAlchemy/GeoAlchemy2 配合

# 示例:使用 WKB 与 GeoAlchemy2 交互的模式
from shapely import to_wkb, from_wkb, Point

# 写入数据库前
point = Point(116.4, 39.9)
wkb_for_db = to_wkb(point, hex=True)

# SQL 示例(伪代码)
sql_insert = f"""
INSERT INTO locations (name, geom)
VALUES ('北京', ST_GeomFromWKB(decode('{wkb_for_db}', 'hex'), 4326))
"""
print(f"插入 SQL 示例:\n{sql_insert}")

# 从数据库读取后
# 假设 row['geom'] 返回 WKB hex 字符串
mock_db_result = wkb_for_db
restored_point = from_wkb(mock_db_result)
print(f"从 DB 还原: {restored_point}")

格式选择指南

何时使用哪种格式

# 格式选择参考表
format_guide = """
┌──────────┬────────────────┬──────────────┬──────────────┐
│ 格式     │ 适用场景       │ 优点         │ 缺点         │
├──────────┼────────────────┼──────────────┼──────────────┤
│ WKT      │ 调试、日志     │ 人类可读     │ 体积大       │
│          │ SQL 查询       │ 易于检查     │ 解析较慢     │
├──────────┼────────────────┼──────────────┼──────────────┤
│ WKB      │ 数据库存储     │ 体积小       │ 不可读       │
│          │ 高性能传输     │ 解析最快     │ 需要工具查看 │
├──────────┼────────────────┼──────────────┼──────────────┤
│ GeoJSON  │ Web API        │ JSON 生态    │ 体积最大     │
│          │ 前端展示       │ 广泛支持     │ 仅 WGS84    │
├──────────┼────────────────┼──────────────┼──────────────┤
│ Pickle   │ Python 内部    │ 最快序列化   │ Python 专用  │
│          │ 缓存           │ 支持所有类型 │ 安全风险     │
└──────────┴────────────────┴──────────────┴──────────────┘
"""
print(format_guide)

小结

本章介绍了 Shapely 中几何体序列化与反序列化的完整方案:

  • WKT:文本格式,可读性好,适合调试和 SQL 交互
  • WKB:二进制格式,体积小速度快,适合存储和高性能场景
  • GeoJSON:JSON 格式,Web 应用首选,广泛的生态支持
  • Pickle:Python 原生格式,适合内部缓存和多进程

关键选择原则:

  1. 调试输出:使用 WKT,rounding_precision 控制精度
  2. 数据库存储:使用 WKB,体积小、解析快
  3. Web API:使用 GeoJSON,前端友好
  4. 内部缓存:使用 WKB 或 Pickle
  5. 批量处理:使用 NumPy 数组 + 向量化函数

掌握这些序列化技术,可以在不同系统和组件之间高效地传递空间数据。