在Python中减去多边形并转换为无孔多边形

-1 投票
1 回答
63 浏览
提问于 2025-04-13 17:33

我有几个蓝色和红色的多边形。我想把红色的从蓝色的里面减去。

这样做之后,剩下的一些多边形可能会有孔。我希望把那些有孔的多边形转换成没有孔的多边形。

我目前尝试过的

from typing import TypedDict
from shapely.geometry import MultiPolygon, Polygon


class Coords(TypedDict):
    x: list[float]
    y: list[float]


def subtract_polygons(group_a: list[Coords], group_b: list[Coords]):
    # Convert polygons to Shapely Polygon objects
    polygons_a = [Polygon(zip(group["x"], group["y"])) for group in group_a]
    polygons_b = [Polygon(zip(group["x"], group["y"])) for group in group_b]

    # Create a "negative" polygon for the hole in group B
    negative_polygons_b = [polygon.exterior for polygon in polygons_b]

    # Subtract each polygon in polygons_b from each polygon in polygons_a
    result_polygons = []
    for polygon_a in polygons_a:
        for negative_polygon_b in negative_polygons_b:
            result_polygon = polygon_a.difference(negative_polygon_b)
            result_polygons.append(result_polygon)

    # Convert the resulting geometry to MultiPolygon
    result_multipolygon = MultiPolygon(result_polygons)

    print("polygons_a", polygons_a)
    print("polygons_b", polygons_b)
    print("negative_polygons_b", negative_polygons_b)
    print("result_multipolygon", result_multipolygon)

group_a: list[Coords] = [
    {"x": [100, 200, 200, 100, 100], "y": [100, 100, 200, 200, 100]},
    {"x": [130, 230, 230, 130, 130], "y": [130, 130, 230, 230, 130]},
    {"x": [180, 280, 280, 180, 180], "y": [180, 180, 280, 280, 180]},
]
group_b: list[Coords] = [
    {"x": [150, 175, 175, 150, 150], "y": [150, 150, 175, 175, 150]},
    {"x": [150, 250, 250, 150, 150], "y": [220, 220, 320, 320, 220]},
]

subtract_polygons(group_a, group_b)

期望的结果:

注意那条小线是随便画的。我只是想展示这是一个单一的多边形,在这种情况下是凹的,而且没有孔。

在这里输入图片描述

输入和实际结果:

在这里输入图片描述

控制台输出:

polygons_a [
<POLYGON ((100 100, 200 100, 200 200, 100 200, 100 100))>,
<POLYGON ((130 130, 230 130, 230 230, 130 230, 130 130))>,
<POLYGON ((180 180, 280 180, 280 280, 180 280, 180 180))>
]

polygons_b [
<POLYGON ((150 150, 175 150, 175 175, 150 175, 150 150))>,
<POLYGON ((150 220, 250 220, 250 320, 150 320, 150 220))>
]

negative_polygons_b [
<LINEARRING (150 150, 175 150, 175 175, 150 175, 150 150)>,
<LINEARRING (150 220, 250 220, 250 320, 150 320, 150 220)>
]

result_multipolygon MULTIPOLYGON (
((100 200, 200 200, 200 100, 100 100, 100 200)),
((100 200, 200 200, 200 100, 100 100, 100 200)),
((130 230, 230 230, 230 130, 130 130, 130 230)),
((230 130, 130 130, 130 230, 150 230, 230 230, 230 220, 230 130)),
((180 280, 280 280, 280 180, 180 180, 180 280)),
((280 280, 280 180, 180 180, 180 220, 180 280, 250 280, 280 280))
)

1 个回答

1

如果我理解你想要做的事情没错的话,你的脚本里有几个问题:

  • polygon.exterior 返回的是一个环形线,而不是一个多边形,所以你不能直接用它来做差集运算。
  • 你想把组 b 中的每个多边形从组 a 中的每个多边形中减去,但你的循环没有做到这一点。
  • 根据你提供的示例输出,你希望结果是合并在一起的。

修正后的脚本:

from typing import TypedDict
from matplotlib import pyplot as plt
import shapely
from shapely.geometry import Polygon
from shapely.plotting import plot_polygon


class Coords(TypedDict):
    x: list[float]
    y: list[float]


def subtract_polygons(group_a: list[Coords], group_b: list[Coords]):
    # Convert polygons to Shapely Polygon objects
    polygons_a = [Polygon(zip(group["x"], group["y"])) for group in group_a]
    polygons_b = [Polygon(zip(group["x"], group["y"])) for group in group_b]

    # Create a "negative" polygon for the hole in group B
    negative_polygons_b = [Polygon(polygon.exterior) for polygon in polygons_b]

    # Subtract each polygon in polygons_b from each polygon in polygons_a
    result_polygons = []
    for polygon_a in polygons_a:
        result_polygon = polygon_a
        for negative_polygon_b in negative_polygons_b:
            result_polygon = result_polygon.difference(negative_polygon_b)

        result_polygons.append(result_polygon)

    return shapely.union_all(result_polygons)


group_a: list[Coords] = [
    {"x": [100, 200, 200, 100, 100], "y": [100, 100, 200, 200, 100]},
    {"x": [130, 230, 230, 130, 130], "y": [130, 130, 230, 230, 130]},
    {"x": [180, 280, 280, 180, 180], "y": [180, 180, 280, 280, 180]},
]
group_b: list[Coords] = [
    {"x": [150, 175, 175, 150, 150], "y": [150, 150, 175, 175, 150]},
    {"x": [150, 250, 250, 150, 150], "y": [220, 220, 320, 320, 220]},
]

result = subtract_polygons(group_a, group_b)

# Plot
polygons_a = [Polygon(zip(group["x"], group["y"])) for group in group_a]
polygons_b = [Polygon(zip(group["x"], group["y"])) for group in group_b]

for polygon_a in polygons_a:
    plot_polygon(polygon_a)
for polygon_b in polygons_b:
    plot_polygon(polygon_b, color="red")
plt.show()
plot_polygon(result)
plt.show()

结果:

在这里输入图片描述

撰写回答