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.
Ubuntu 18.04.2 LTS
Python 3.6.7 - Shapely 1.6.4.post2 (von PyPI mit pip installiert)
In Ordnung. Ich sehe das Problem hier.
Optisch sehen diese Linienfolgen wie folgt aus:
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.
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 Überquerungline
und nehmen Sie den Unterschied von nur denjenigen. Aber das würde den Fall nicht lösen, dass ein einzelner LineStringsplitter
zurückhakt, um denline
zu berühren, den er an einem anderen Punkt kreuzt. Ich denke, die einzige Möglichkeit, hier ein konsistentes Verhalten zu erzielen, während Siedifference
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 vonline
diesplitter
berührt. Tatsächlich wird dieser Fall getestet . Aber unser aktueller Fall, bei dem die Grenze vonsplitter
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.