【问题标题】:Intersection of a Shapely polygon with a Matplotlib wedgeShapely 多边形与 Matplotlib 楔形的交集
【发布时间】:2019-08-07 09:17:27
【问题描述】:

在这种情况下,我正在绘制matplotlib.patches.Wedge 对象并缓冲shapely.geometry.LineString 对象。我需要计算这两个对象的重叠区域。但是,Wedge 是一个 matplotlib.wedges 对象,不能与 Shapely 的 .intersection() 方法一起使用。

我该怎么做? 这是一些代码:

from shapely.geometry import LineString
from matplotlib.patches import Wedge
from matplotlib import pyplot as plt
from descartes.patch import PolygonPatch

width = 5
radius = 1
rich = 1

circle_patch = Wedge((0, 0), radius+3,
                     0, 360, 3)

fig, ax = plt.subplots()

ax.add_patch(circle_patch)

ax.plot(0, 0, 'xr')
plt.autoscale()

coords = [
    [0, 0],
    [0, 1],
    [0, 2],
    [1, 2],
    [2, 2]
]

stick = LineString(coords)

stick_patch = PolygonPatch(stick.buffer(0.5))

ax.add_patch(stick_patch)

x, y = stick.xy
ax.plot(x, y, 'r-', zorder=1)

plt.show()

area = stick.buffer(0.5).intersection(circle_patch).area

附:它必须是环形,而不是圆形

【问题讨论】:

标签: python matplotlib intersection shapely


【解决方案1】:

想通了。 matplotlib.patches 类有一个 ._path.vertices 成员,它为您提供楔形对象的坐标数组,然后您可以将其与 Shapely 的 LinearRing 类一起使用来创建一个 Shapely 对象,如下所示:

from shapely.geometry import LineString, LinearRing
from matplotlib.patches import Wedge

width = 5
radius = 1
rich = 1

circle_patch = Wedge((0, 0), radius,
                     0, 360,)

ring_coords = circle_patch._path.vertices
ring_coords = ring_coords[(ring_coords[:, 0] != 0) & (ring_coords[:, 1] != 0)]

ring = LinearRing(ring_coords)

然而,它确实需要操纵坐标数组,我认为这不是最可靠的方法,但它对我有用。圆环也不是完全光滑的,但我确信可以使用一些或其他 NumpyScipy 函数对坐标数组进行一些平滑处理。

编辑:要创建单个楔形线,必须删除楔形的width 成员。但是,稍后可以使用 Shapely 的 buffer() 函数重新合并。

【讨论】:

  • 您更改了问题中的原始Wedge。有了那个,您将在生成的多边形中缺少一块。
【解决方案2】:

最简单的解决方案是不使用 Matplotlib 补丁,而是首先使用 Shapely 构造楔形多边形:

import matplotlib.pyplot as plt
from descartes.patch import PolygonPatch
from shapely.geometry import LineString, Point

outer_circle = Point(0, 0).buffer(4)
inner_circle = Point(0, 0).buffer(1)
wedge = outer_circle.difference(inner_circle)

stick = LineString([(0, 0), (0, 2), (2, 2)])
buffered_stick = stick.buffer(0.5)

intersection = buffered_stick.intersection(wedge)

wedge_patch = PolygonPatch(wedge)
stick_patch = PolygonPatch(buffered_stick, alpha=0.5, hatch='/')
intersection_patch = PolygonPatch(intersection, alpha=0.5, hatch='.')

fig, ax = plt.subplots()
ax.add_patch(wedge_patch)
ax.add_patch(stick_patch)
ax.add_patch(intersection_patch)
plt.autoscale()


如果由于某种原因这是不可能的,而您必须使用 Matplotlib 的 Wedge,那么我可以想出两种方法来获得它与 Shapely 多边形的交集区域。在他们两个中,我首先将补丁转换为 Shapely 多边形。你probably can't 只使用 Matplotlib 获取交叉区域。

1) 在 Matplotlib 的补丁上使用 .get_path() 方法,您可以从中提取 vertices 作为 NumPy 数组,并使用 asPolygon 将其转换为 Shapely 多边形:

import matplotlib.pyplot as plt
from descartes.patch import PolygonPatch
from matplotlib.patches import Wedge
from shapely.geometry import asPolygon, LineString

wedge_patch = Wedge(center=(0, 0), 
                    r=4,
                    theta1=0, 
                    theta2=360, 
                    width=3)
stick = LineString([(0, 0), (0, 2), (2, 2)])
buffered_stick = stick.buffer(0.5)

wedge_path = wedge_patch.get_path()
wedge_polygon = asPolygon(wedge_path.vertices).buffer(0)
intersection = buffered_stick.intersection(wedge_polygon)

stick_patch = PolygonPatch(buffered_stick, alpha=0.5, hatch='/')
intersection_patch = PolygonPatch(intersection, alpha=0.5, hatch='.')

fig, ax = plt.subplots()
ax.add_patch(wedge_patch)
ax.add_patch(stick_patch)
ax.add_patch(intersection_patch)
plt.autoscale()

注意我应用于楔形多边形的buffer(0)。这是 Shapely 中的一个常见技巧,可以从无效多边形中生成有效多边形。在your answer 中,您在从ring_coords 中删除零时会执行类似的操作。

2) 通过访问Wedge 属性:centerrwidth,并使用它们重新创建多边形:

import matplotlib.pyplot as plt
from descartes.patch import PolygonPatch
from matplotlib.patches import Wedge
from shapely.geometry import LineString, Point

wedge_patch = Wedge(center=(0, 0), 
                    r=4,
                    theta1=0, 
                    theta2=360, 
                    width=3)
stick = LineString([(0, 0), (0, 2), (2, 2)])
buffered_stick = stick.buffer(0.5)

outer_circle = Point(wedge_patch.center).buffer(wedge_patch.r)
inner_circle = Point(wedge_patch.center).buffer(wedge_patch.r - wedge_patch.width)
wedge_polygon = outer_circle.difference(inner_circle)
intersection = buffered_stick.intersection(wedge_polygon)

stick_patch = PolygonPatch(buffered_stick, alpha=0.5, hatch='/')
intersection_patch = PolygonPatch(intersection, alpha=0.5, hatch='.')

fig, ax = plt.subplots()
ax.add_patch(wedge_patch)
ax.add_patch(stick_patch)
ax.add_patch(intersection_patch)
plt.autoscale()

所有解决方案都提供相同的视觉输出。

所有方法给出的区域大致相同:

>>> intersection.area
3.3774012986988513  # 1st case
3.3823210603713694  # 2nd case and the original without Matplotlib

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-28
    • 1970-01-01
    • 1970-01-01
    • 2019-08-26
    • 2018-05-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多