You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Shapely中Voronoi多边形与多边形相交的结果差异及性能优化

Shapely Voronoi多边形与目标多边形相交的问题与优化方案

问题背景

我正在使用Shapely进行地理数据相交运算,并用PyShp将结果写入shapefile,但对intersection的工作原理存在疑惑。

步骤复现

1. 生成Voronoi多边形

通过以下代码创建点集并生成Voronoi多边形:

# (1)
from shapely import LineString, MultiPoint, Point, Polygon, MultiPolygon
from shapely.geometry import shape
from shapely.constructive import voronoi_polygons
from shapely import intersection
import shapefile

output_shapefile = "/tmp/simple_test_01.shp"
points = MultiPoint([Point(1,1), Point(2,2), Point(4,3), Point(2,4), Point(2,5), Point(6,5), Point(5,4), Point(7,1)])
myVoronoi = voronoi_polygons(points)
#>>> myVoronoi
#<GEOMETRYCOLLECTION (POLYGON ((-5 -5, -5 4.625, -4.5 4.5, 0 3, 4 -1, 4 -5, -...>
n = 0
with shapefile.Writer(output_shapefile, shapeType=5) as w:
    w.field("ID", "N")
    for geom in myVoronoi.geoms:
        w.shape(geom)  
        w.record(n)
        n += 1

生成的Voronoi多边形在ArcMap中可视化后,包含多个围绕绿色标注点的多边形区域。

2. 创建目标相交多边形

创建用于相交的目标多边形:

# (2)
polygon_to_intersect = Polygon([Point(0,0), Point(2,8), Point(4,3.7), Point(10,4.5), Point(5,-4), Point(0,0)])
output_shapefile = "/tmp/simple_test_02.shp"
with shapefile.Writer(output_shapefile, shapeType=5) as w:
    w.field("ID", "N")
    w.shape(polygon_to_intersect)  
    w.record(1)

该多边形在ArcMap中显示为红色轮廓的不规则多边形。

3. 直接执行整体相交(不符合预期)

执行整体相交运算:

# (3)
intersected = intersection(myVoronoi, polygon_to_intersect)

>>> intersected
<POLYGON ((0.6 2.4, 0.75 3, 1.125 4.5, 2 8, 3.553 4.66, 3.739 4.261, 4 3.7, ...>

output_shapefile = "/tmp/simple_test_03.shp"
n = 0
with shapefile.Writer(output_shapefile) as w:
    w.field("ID", "N")
    w.shape(intersected)  
    w.record(n)

得到的结果是单个Polygon,而非预期的MultiPolygon,仅为目标多边形与所有Voronoi多边形合并后的相交区域,丢失了单个Voronoi多边形的独立相交结果。

4. 逐个Voronoi多边形相交(符合预期但性能差)

逐个对每个Voronoi多边形执行相交运算:

# (4)
output_shapefile = "/tmp/simple_test_04.shp"
multipol = []
for geom in myVoronoi.geoms:
    multipol.append(intersection(geom, polygon_to_intersect))

n = 0
with shapefile.Writer(output_shapefile) as w:
    w.field("ID", "N")
    for pol in multipol:
        w.shape(pol)  
        w.record(n)
        n += 1

得到了预期结果:每个着色区域对应单个Voronoi多边形与目标多边形的相交部分。但在真实场景中,当Voronoi多边形数量达18000+时,该方法耗时近25分钟,存在性能问题。

5. 转换为MultiPolygon后相交(仍不符合预期)

尝试将Voronoi的GeometryCollection转换为MultiPolygon后再执行相交:

# (5)
output_shapefile = "/tmp/simple_test_05.shp"

myVoronoi2 = MultiPolygon(myVoronoi)
>>> myVoronoi2
<MULTIPOLYGON (((-5 -5, -5 4.625, -4.5 4.5, 0 3, 4 -1, 4 -5, -5 -5)), ((-5 1...>

intersected2 = intersection(myVoronoi2, polygon_to_intersect)

>>> intersected2
<POLYGON ((0.6 2.4, 0.75 3, 1.125 4.5, 2 8, 3.553 4.66, 3.739 4.261, 4 3.7, ...>

n = 0
with shapefile.Writer(output_shapefile) as w:
    w.field("ID", "N")
    w.shape(intersected2)  
    w.record(n)

>>> intersected2 == intersected
True

结果仍与直接整体相交一致,还是单个Polygon,无法保留独立的相交结果。

原理理解

经提示,Shapely的intersection方法采用并集语义:当传入集合类几何(如GeometryCollection、MultiPolygon)时,会先将所有子几何合并为一个整体,再与目标几何执行相交运算,因此无法保留单个子几何的独立相交结果。

优化方案

尝试使用Rtree进行空间索引优化但效果不佳,后续通过以下策略将运行时间缩短至4分钟:

  • 创建目标多边形的简化版本(降低几何复杂度)
  • 对每个Voronoi多边形先进行快速判断:
    • 若Voronoi多边形完全在简化后的目标多边形内部,则直接保留该多边形,无需执行相交运算
    • 若不在内部,再执行与原目标多边形的相交运算

内容的提问来源于stack exchange,提问作者Mike Duke

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 13:17:44