Shapely: ops.split 与 LineStrings 和 MultiLineStrings 不一致的行为

创建于 2019-04-11  ·  5评论  ·  资料来源: Toblerity/Shapely

预期行为和实际行为以及重现问题的步骤

用相交的线串 B 分割线串 A 不会产生预期的输出(返回 A)。 使用包含 B 和 C(C 也与 A 相交)的多线串拆分 A 会产生所需的输出(3 段)。 这似乎不一致。

from shapely.ops import split
from shapely.geometry import LineString, MultiLineString

A = LineString([(0, 0), (10, 0)])
B = LineString([(5, 0), (5, 5)])
C = LineString([(1, -1), (1, 1)])
assert (split(A, B).wkt == "GEOMETRYCOLLECTION (LINESTRING (0 0, 10 0))")
# Does not split
# Expected: "GEOMETRYCOLLECTION (LINESTRING (0 0, 5 0), LINESTRING (5 0, 10 0))"

assert (A.intersection(B).wkt == "POINT (5 0)")
# Although A and B do intersect

assert (split(A, MultiLineString([B, C])).wkt ==
        "GEOMETRYCOLLECTION (LINESTRING (0 0, 1 0), LINESTRING (1 0, 5 0), LINESTRING (5 0, 10 0))")
# OK - A is split by both B and C - but A was not split by B in the previous example.

操作系统

Ubuntu 18.04.2 LTS

匀称的版本和出处

Python 3.6.7 - Shapely 1.6.4.post2(使用 pip 从 PyPI 安装)

最有用的评论

我认为这会很好,是的。 这种行为对我来说很有意义。

有一段时间,我认为我们可以过滤 MultiLineString splitter的 goem,为那些穿过line过滤,并只取那些的差异。 但这并不能解决单个 LineString splitter钩回以触摸它在另一点穿过的line情况。 我认为在使用difference进行繁重工作时获得一致行为的唯一方法是拆分接触的线性几何图形。

我怀疑可能crosses被使用了,所以当只有line的边界接触splitter时,函数会提前返回。 事实上,这个案例是针对. 但是我们目前的情况,其中splitter的边界接触line ,不在测试中,并且可能是一个盲点。 但是,我是一个 Shapely 本地人,对其他简单的功能库没有太多经验。 而且我不知道仅在交叉时分裂是否是线性几何的标准行为。

那是 5 年前,但如果@georgeouzou记得,也许他可以确认或解释为什么使用crosses

如果我们想在测试的情况下早点返回,我们也可以吃蛋糕并吃掉它,但在这个问题的情况下继续拆分。 这将需要直接使用relate 。 但我怀疑两种方式都会有很大的性能差异。

所有5条评论

行。 我在这里看到了问题。

从视觉上看,这些线串如下所示:

image

当您将水平线 ( A ) 与顶部 ( B ) 上仅接触A的大垂直线分开时,没有任何反应。 但是用C分割A确实有效,因为C穿过A

现在,当您将AMultiLineString([B, C])拆分时,它会拆分为三个线串,而不是您期望的两个。 我同意这似乎不一致。

导致这种情况的代码实际上很容易访问(永久链接)。

    <strong i="26">@staticmethod</strong>
    def _split_line_with_line(line, splitter):
        """Split a LineString with another (Multi)LineString or (Multi)Polygon"""

        # if splitter is a polygon, pick it's boundary
        if splitter.type in ('Polygon', 'MultiPolygon'):
            splitter = splitter.boundary

        assert(isinstance(line, LineString))
        assert(isinstance(splitter, LineString) or isinstance(splitter, MultiLineString))

        if splitter.crosses(line):
            # The lines cross --> return multilinestring from the split
            return line.difference(splitter)
        elif splitter.relate_pattern(line, '1********'):
            # The lines overlap at some segment (linear intersection of interiors)
            raise ValueError('Input geometry segment overlaps with the splitter.')
        else:
            # The lines do not cross --> return collection with identity line
            return [line]

您可以看到splitter需要穿过line才能开始任何拆分。 但是一旦通过该检查点,就会对difference进行简单调用以生成分割几何图形。 但是difference不区分穿越和仅仅接触! 因此,如果在任何时候splitter line交叉,那么所有仅仅是接触点都将被拆分。

@Jeremiah-England 感谢您对此进行深入研究! 似乎,至少对于线条,我们可以将交叉测试更改为接触测试并获得不那么令人惊讶的结果? 你怎么看?

我认为这会很好,是的。 这种行为对我来说很有意义。

有一段时间,我认为我们可以过滤 MultiLineString splitter的 goem,为那些穿过line过滤,并只取那些的差异。 但这并不能解决单个 LineString splitter钩回以触摸它在另一点穿过的line情况。 我认为在使用difference进行繁重工作时获得一致行为的唯一方法是拆分接触的线性几何图形。

我怀疑可能crosses被使用了,所以当只有line的边界接触splitter时,函数会提前返回。 事实上,这个案例是针对. 但是我们目前的情况,其中splitter的边界接触line ,不在测试中,并且可能是一个盲点。 但是,我是一个 Shapely 本地人,对其他简单的功能库没有太多经验。 而且我不知道仅在交叉时分裂是否是线性几何的标准行为。

那是 5 年前,但如果@georgeouzou记得,也许他可以确认或解释为什么使用crosses

如果我们想在测试的情况下早点返回,我们也可以吃蛋糕并吃掉它,但在这个问题的情况下继续拆分。 这将需要直接使用relate 。 但我怀疑两种方式都会有很大的性能差异。

@Jeremiah-England 我的记忆有点模糊,但再次看到代码我可以确认这是一个盲点。 代码还应测试当前案例是否完整。 你能继续改变吗?

@georgeouzou ,感谢您抽出时间来查看!

而且,是的,如果每个人都可以,我想敲定这个案例并在某个时候提交 PR。

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

相关问题

sgillies picture sgillies  ·  5评论

LostFan123 picture LostFan123  ·  3评论

jrobichaud picture jrobichaud  ·  3评论

sgillies picture sgillies  ·  6评论

doctor-ian picture doctor-ian  ·  4评论