匀称的.contains()方法,但包括边界?

时间:2019-07-06 10:52:13

标签: python shapely

我正在使用Shapely多边形,我需要一种删除较大多边形中所有较小多边形的方法。我尝试使用Shapely提供的.contains()方法,但是如果较小的多边形不完全位于较大的多边形内,则该方法不会返回True

基本上,我希望使用类似.contains()的方法,但是如果多边形位于外部多边形的边界(如图片上),它将返回True

here

以下是以wkt格式显示的图片中的多边形:

绿色的:

POLYGON Z ((14.4265764858233823 45.3396418051734784 0.0000000000000000, 14.4267228266679606 45.3395430970275015 0.0000000000000000, 14.4266753563381904 45.3394727193694536 0.0000000000000000, 14.4265290154936121 45.3395714275154376 0.0000000000000000, 14.4265764858233823 45.3396418051734784 0.0000000000000000))`  

红色的:

POLYGON Z ((14.4265450394689161 45.3395951840357725 0.0000000000000000, 14.4265695507109317 45.3395786509942837 0.0000000000000000, 14.4265802185605700 45.3395944667317679 0.0000000000000000, 14.4265982245953417 45.3395823215079616 0.0000000000000000, 14.4265715327703994 45.3395427492501426 0.0000000000000000, 14.4265290154936121 45.3395714275154376 0.0000000000000000, 14.4265450394689161 45.3395951840357725 0.0000000000000000))

我也尝试使用.intersects()方法,但对于给定多边形之外的具有某些公共边界的多边形,我会返回True

希望您能理解我的需求,如果有人知道解决方案,我将非常感谢。

1 个答案:

答案 0 :(得分:1)

通常,contains方法在测试一个多边形是否在另一个多边形内并且具有公共边界时应该起作用。例如,如果您使用以下简单示例,它将按预期工作:

from shapely.geometry import Polygon

a = Polygon([(0, 0), (2, 0), (2, 2), (0, 2)])
b = Polygon([(0, 0), (1, 0), (1, 1), (0, 1)])
a.contains(b)
# True

enter image description here

但是经常发生的是由于精度误差,内部多边形从外部仅出现了一点点,并且测试失败。

例如,在这里,我绘制了多边形并放大了左上的交点:

import matplotlib.pyplot as plt

plt.plot(*green.exterior.xy, c='g')
plt.plot(*red.exterior.xy, c='r')

您会发现线条之间并不是完美地重叠在一起:

enter image description here

有几种方法可以解决此问题。例如,第一个建议是在How to deal with rounding errors in Shapely和某些Shapely issues on GitHub中提出的:

  1. 缩小较小的多边形或将较大的多边形稍微扩展一点:

    big.contains(small.buffer(-1e-14))
    # True
    big.buffer(1e-14).contains(small)
    # True
    
  2. 检查位于较大多边形之外的较小多边形的面积接近零:

    small.difference(big).area < 1e-14
    # True
    
  3. 检查较小多边形的每个顶点到较大多边形的距离是否接近零:

    from shapely.geometry import Point
    
    vertices = map(Point, small.exterior.coords)
    distances = map(big.distance, vertices)
    all(distance < 1e-14 for distance in distances) 
    # True
    

也许有更多的方法可以执行测试,但我认为这些就足够了。