为什么 MultiPolygon 的 MultiPolygon 比它的输入小?

Why is a MultiPolygon of a MultiPolygon smaller than its input?

我对以下输出感到困惑:

>>> from shapely.geometry import Polygon, MultiPolygon, mapping
>>> p1 = Polygon([(0,0), (0, 1), (1, 1), (1, 0)])
>>> p2 = Polygon([(0,0), (0, 1), (1, 1), (1, 2)])
>>> mapping(MultiPolygon([p1, p2]).convex_hull)
{'type': 'Polygon', 'coordinates': (((0.0, 0.0), (0.0, 1.0), (1.0, 2.0), (1.0, 0.0), (0.0, 0.0)),)}
>>> mapping(MultiPolygon([MultiPolygon([p1, p2])]).convex_hull)
{'type': 'Polygon', 'coordinates': (((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)),)}

我假设如果我给它一个 MultiPolygon 作为输入,MultiPolygon 将 return 相同(不一定相同)的对象。所以我预计

(((0.0, 0.0), (0.0, 1.0), (1.0, 2.0), (1.0, 0.0), (0.0, 0.0)),)

而不是 returned 输出。

对于 shapely 的开发版本,构造 MultiPolygon([MultiPolygon([p1, p2])]) 引发 ValueError

更具体地说,MultiPolygon 的构造函数似乎接受另一个 MultiPolygonPolygon 的列表。它 calls the function geos_multipolygon_from_polygons which performs 以下检查:

# This function does not accept sequences of MultiPolygons: there is
# no implicit flattening.
if isinstance(obs[0], MultiPolygon):
    raise ValueError("Sequences of multi-polygons are not valid arguments")

如果删除此检查(严格来说,应该对 obs 列表的所有元素执行),函数将继续:

subs = (c_void_p * L)()

for i, ob in enumerate(obs):
    if isinstance(ob, polygon.Polygon):
        shell = ob.exterior
        holes = ob.interiors
    else:
        shell = ob[0]
        holes = ob[1]

    geom, ndims = polygon.geos_polygon_from_py(shell, holes)
    subs[i] = cast(geom, c_void_p)

return (lgeos.GEOSGeom_createCollection(6, subs, L), N)

这里,如果obs列表中的一个元素不是Polygon,索引用于提取shellholes。但是,对于您的特定情况下的 MultiPolygon,这只会提取单个多边形 p1p2holes 似乎不影响 return 语句的结果,因此该函数将为每个 MultiPolygon 仅提取其第一个组件。

以你的例子为例:

from shapely.geometry import Polygon, MultiPolygon, mapping
p1 = Polygon([(0,0), (0, 1), (1, 1), (1, 0)])
p2 = Polygon([(0,0), (0, 1), (1, 1), (1, 2)])

M1 = MultiPolygon([p1, p2])
M2 = MultiPolygon([M1])
print(p1) #POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))
print(M2) #MULTIPOLYGON (((0 0, 0 1, 1 1, 1 0, 0 0)))

如果将表达式MultiPolygon([MultiPolygon([p1, p2])])修改为MultiPolygon(MultiPolygon([p1, p2])),得到的凸包符合预期。