Shapely: ops.split inkonsistentes Verhalten mit LineStrings und MultiLineStrings

Erstellt am 11. Apr. 2019  ·  5Kommentare  ·  Quelle: Toblerity/Shapely

Erwartetes Verhalten und tatsächliches Verhalten und Schritte zur Reproduktion des Problems

Das Teilen einer Linienfolge A mit einer sich überschneidenden Linienfolge B erzeugt nicht die erwartete Ausgabe (gibt A zurück). Das Aufteilen von A mit einem Multilinestring, der B und C enthält (C schneidet auch A) erzeugt die gewünschte Ausgabe (3 Segmente). Dies scheint inkonsistent.

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.

Betriebssystem

Ubuntu 18.04.2 LTS

Formschöne Version und Provenienz

Python 3.6.7 - Shapely 1.6.4.post2 (von PyPI mit pip installiert)

Hilfreichster Kommentar

Ich denke, das würde gut funktionieren, ja. Und das Verhalten macht für mich Sinn.

Für ein bisschen, dachte ich , dass wir die goems in einem Multi filtern könnten splitter für die Überquerung line und nehmen Sie den Unterschied von nur denjenigen. Aber das würde den Fall nicht lösen, dass ein einzelner LineString splitter zurückhakt, um den line zu berühren, den er an einem anderen Punkt kreuzt. Ich denke, die einzige Möglichkeit, hier ein konsistentes Verhalten zu erzielen, während Sie difference für das schwere Heben verwenden, besteht darin, sich berührende lineare Geometrien aufzuteilen.

Ich vermute, dass möglicherweise crosses wurde, sodass die Funktion früher zurückgegeben wurde, wenn nur die Grenze von line die splitter berührt. Tatsächlich wird dieser Fall getestet . Aber unser aktueller Fall, bei dem die Grenze von splitter line splitter berührt, befindet sich nicht in den Tests und war möglicherweise ein blinder Fleck. Ich bin jedoch ein Shapely-Eingeborener ohne viel Erfahrung mit anderen einfachen Feature-Bibliotheken. Und ich weiß nicht, ob nur das Aufspalten beim Kreuzen Standardverhalten für lineare Geometrien ist.

Es war vor 5 Jahren, aber wenn @georgeouzou sich erinnert, könnte er vielleicht bestätigen oder erklären, warum crosses verwendet wurde?

Wir können unseren Kuchen haben und ihn auch essen, wenn wir in dem getesteten Fall früher zurückkehren möchten, aber in diesem Fall mit dem Splittern fortfahren. Dafür müsste relate direkt verwendet werden. Aber ich bezweifle, dass es so oder so einen großen Leistungsunterschied geben würde.

Alle 5 Kommentare

In Ordnung. Ich sehe das Problem hier.

Optisch sehen diese Linienfolgen wie folgt aus:

image

Wenn Sie die horizontale geteilt (A) durch den großen senkrecht nach oben (B) , die A nur berührt, passiert nichts. Aber das Teilen von A durch C funktioniert, weil C A kreuzt .

Wenn Sie nun A durch MultiLineString([B, C]) teilen, wird es in drei Linienfolgen aufgeteilt, nicht in zwei, wie Sie es erwarten würden. Ich stimme zu, dass dies inkonsistent erscheint.

Der Code, der dies verursacht, ist eigentlich ziemlich zugänglich ( Permalink ).

    <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]

Sie können sehen, dass splitter erforderlich ist, um line zu kreuzen, damit eine Aufteilung beginnen kann. Aber sobald dieser Prüfpunkt passiert ist, wird ein einfacher Aufruf von difference , um die geteilten Geometrien zu generieren. Aber difference unterscheidet nicht zwischen Überqueren und bloßem Berühren! Wenn also an irgendeinem Punkt splitter line splitter kreuzt, werden alle sich nur berührenden Punkte geteilt.

@Jeremiah-England, danke, dass du dich damit befasst hast! Es scheint, als könnten wir zumindest für Linien den Kreuztest in einen Berührungstest ändern und weniger überraschende Ergebnisse erzielen? Was denkst du darüber?

Ich denke, das würde gut funktionieren, ja. Und das Verhalten macht für mich Sinn.

Für ein bisschen, dachte ich , dass wir die goems in einem Multi filtern könnten splitter für die Überquerung line und nehmen Sie den Unterschied von nur denjenigen. Aber das würde den Fall nicht lösen, dass ein einzelner LineString splitter zurückhakt, um den line zu berühren, den er an einem anderen Punkt kreuzt. Ich denke, die einzige Möglichkeit, hier ein konsistentes Verhalten zu erzielen, während Sie difference für das schwere Heben verwenden, besteht darin, sich berührende lineare Geometrien aufzuteilen.

Ich vermute, dass möglicherweise crosses wurde, sodass die Funktion früher zurückgegeben wurde, wenn nur die Grenze von line die splitter berührt. Tatsächlich wird dieser Fall getestet . Aber unser aktueller Fall, bei dem die Grenze von splitter line splitter berührt, befindet sich nicht in den Tests und war möglicherweise ein blinder Fleck. Ich bin jedoch ein Shapely-Eingeborener ohne viel Erfahrung mit anderen einfachen Feature-Bibliotheken. Und ich weiß nicht, ob nur das Aufspalten beim Kreuzen Standardverhalten für lineare Geometrien ist.

Es war vor 5 Jahren, aber wenn @georgeouzou sich erinnert, könnte er vielleicht bestätigen oder erklären, warum crosses verwendet wurde?

Wir können unseren Kuchen haben und ihn auch essen, wenn wir in dem getesteten Fall früher zurückkehren möchten, aber in diesem Fall mit dem Splittern fortfahren. Dafür müsste relate direkt verwendet werden. Aber ich bezweifle, dass es so oder so einen großen Leistungsunterschied geben würde.

@Jeremiah-England mein Gedächtnis ist in diesem Fall etwas trübe, aber wenn ich den Code noch einmal sehe, kann ich bestätigen, dass dies ein blinder Fleck war. Der Code sollte auch testen, ob der aktuelle Fall vollständig ist. Könnten Sie mit den Änderungen fortfahren?

Hey @georgeouzou , danke, dass hast ,

Und, ja, wenn es für alle in Ordnung ist, würde ich diesen Fall gerne ausarbeiten und irgendwann eine PR einreichen.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

LostFan123 picture LostFan123  ·  5Kommentare

jrobichaud picture jrobichaud  ·  3Kommentare

doctor-ian picture doctor-ian  ·  4Kommentare

sgillies picture sgillies  ·  5Kommentare

kannes picture kannes  ·  4Kommentare