Shapely: 添加功能以删除第 3 维

创建于 2019-05-05  ·  3评论  ·  资料来源: Toblerity/Shapely

GIS Stack Exchange 上有一个关于将 3D 几何转换为 2D 的老问题: Convert 3D WKT to 2D Shapely Geometry 。 我认为这个功能应该包含在 Shapely 中,所以我们可以使用它,例如:

>>> from shapely.geometry import Polygon
>>> p = Polygon([(0, 0, 0), (1, 0, 0), (1, 1, 0)])
>>> p.wkt
'POLYGON Z ((0 0 0, 1 0 0, 1 1 0, 0 0 0))'
>>> p2 = p.drop_z
>>> p2.wkt
'POLYGON ((0 0, 1 0, 1 1, 0 0))'

我在其中一个答案和文档中看到_此操作不是必需的_因为第三维_对几何分析没有影响_ 。 但是当实现我自己的函数来确定分割几何的左侧时(这还没有实现:https://github.com/Toblerity/Shapely/issues/589),我看到这个功能可以派上用场:

from shapely.geometry import (LinearRing, 
                              LineString, 
                              Polygon)


def is_left(polygon: Polygon,
            line: LineString) -> bool:
    """
    Determines if the polygon is on the left side of the line
    according to:
    https://stackoverflow.com/questions/50393718/determine-the-left-and-right-side-of-a-split-shapely-geometry
    """
    ring = LinearRing([*line.coords, *polygon.centroid.coords])
    return ring.is_ccw

此代码对于 3D 几何图形将失败:

p = Polygon([(0, 0, 0), (1, 0, 0), (1, 1, 0)])
l = LineString([(0, 0, 0), (1, 0, 0)])
is_left(p, l)

会给出这个错误:

AttributeError                            Traceback (most recent call last)
~/miniconda3/lib/python3.7/site-packages/shapely/speedups/_speedups.pyx in shapely.speedups._speedups.geos_linearring_from_py()

AttributeError: 'list' object has no attribute '__array_interface__'

During handling of the above exception, another exception occurred:

IndexError                                Traceback (most recent call last)
<ipython-input-55-555b9e2533fa> in <module>()
----> 1 is_left(p, l)

<ipython-input-52-7fad75b19ce3> in is_left(polygon, line)
      6     https://stackoverflow.com/questions/50393718/determine-the-left-and-right-side-of-a-split-shapely-geometry
      7     """
----> 8     ring = LinearRing([*line.coords, *polygon.centroid.coords])
      9     return ring.is_ccw

~/miniconda3/lib/python3.7/site-packages/shapely/geometry/polygon.py in __init__(self, coordinates)
     51         BaseGeometry.__init__(self)
     52         if coordinates is not None:
---> 53             self._set_coords(coordinates)
     54 
     55     <strong i="18">@property</strong>

~/miniconda3/lib/python3.7/site-packages/shapely/geometry/polygon.py in _set_coords(self, coordinates)
     66     def _set_coords(self, coordinates):
     67         self.empty()
---> 68         ret = geos_linearring_from_py(coordinates)
     69         if ret is not None:
     70             self._geom, self._ndim = ret

~/miniconda3/lib/python3.7/site-packages/shapely/speedups/_speedups.pyx in shapely.speedups._speedups.geos_linearring_from_py()

IndexError: tuple index out of range

这是因为Polygon的质心总是以 2D 形式返回(https://github.com/Toblerity/Shapely/issues/554),而LinearRing不能由具有不同维数的点构成。

如果有drop_z方法,我只会编写ring = LinearRing([*line.drop_z.coords, *polygon.centroid.coords]) ,而不是用line = LineString([xy[:2] for xy in list(line.coords)])之类的东西弄乱代码或为此实现一个函数。 或者更好的是,我会删除仅由原始父多边形中的零组成的冗余第 3 维,我从顶层文件中读取,因此所有子几何都只有 2 维。


Shapely 版本:1.6.4.post1,从 conda 安装。

wontfix

最有用的评论

对于从谷歌来到这里的其他人,我发现了一个非常简单的方法:

def _to_2d(x, y, z):
    return tuple(filter(None, [x, y]))

new_shape = shapely.ops.transform(_to_2d, shape)

(来自 https://github.com/hotosm/tasking-manager/blob/master/server/services/grid/grid_service.py 的@feenster@hunt3ri :heart:)

所有3条评论

@LostFan123我认为删除 Z 值的方法将是 1.7 的适当添加。 谢谢你的建议。

对于从谷歌来到这里的其他人,我发现了一个非常简单的方法:

def _to_2d(x, y, z):
    return tuple(filter(None, [x, y]))

new_shape = shapely.ops.transform(_to_2d, shape)

(来自 https://github.com/hotosm/tasking-manager/blob/master/server/services/grid/grid_service.py 的@feenster@hunt3ri :heart:)

我将关闭此问题以支持上面的 2 行解决方案。 谢谢@Juanlu001

此页面是否有帮助?
0 / 5 - 0 等级