为什么 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
的构造函数似乎接受另一个 MultiPolygon
或 Polygon
的列表。它 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
,索引用于提取shell
和holes
。但是,对于您的特定情况下的 MultiPolygon
,这只会提取单个多边形 p1
和 p2
。 holes
似乎不影响 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]))
,得到的凸包符合预期。
我对以下输出感到困惑:
>>> 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
的构造函数似乎接受另一个 MultiPolygon
或 Polygon
的列表。它 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
,索引用于提取shell
和holes
。但是,对于您的特定情况下的 MultiPolygon
,这只会提取单个多边形 p1
和 p2
。 holes
似乎不影响 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]))
,得到的凸包符合预期。