Suche nach einer pythonischen Methode zur Berechnung der Länge einer WKT-Linienfolge

13

Ich war ziemlich unzufrieden mit der Berechnung der Länge der Linienfolgen in WGS84 in Meilen . Ich habe mich gefragt, ob es eine bequemere, pythonische Methode gibt, um die Länge einer WKT-Linienfolge gemäß einer bestimmten SRID zu berechnen.

Ich denke an etwas wie:

srid="WGS84"
line="LINESTRING(3.0 4.0, 3.1 4.1)"
print length(line, srid)

Ich suche eine genaue Antwort, keine sin\cosAnnäherungen.

Irgendwelche Ideen?

Adam Matan
quelle
tomkralidis, das ist eine GIS-Website. Ihre Antwort ignoriert, dass dies ein Abstand zwischen Geokoordinaten ist (siehe SRID). Shapely an sich kann keine räumlichen Entfernungen berechnen, da es keine Kenntnisse über die Kartenprojektion hat.

Antworten:

18

Das Geopy- Modul liefert die Vincenty-Formel , die genaue Ellipsoidabstände liefert. Verbinden Sie dies mit dem wktLaden in Shapely, und Sie haben einigermaßen einfachen Code:

from geopy import distance
from shapely.wkt import loads

line_wkt="LINESTRING(3.0 4.0, 3.1 4.1)"

# a number of other elipsoids are supported
distance.VincentyDistance.ELLIPSOID = 'WGS-84'
d = distance.distance

line = loads(line_wkt)

# convert the coordinates to xy array elements, compute the distance
dist = d(line.xy[0], line.xy[1])

print dist.meters
scw
quelle
1
+1, hätte +10, wenn ich könnte. Sparte meinem Team Stunden der Programmierung.
Adam Matan
Unterscheidet sich dieser Ansatz von der Antwort von @tomkralidis, wenn sich die Eingabekoordinaten bereits in WGS-84 befinden?
LarsVegas
1
@LarsVegas ja, Shapely verarbeitet nur planare Koordinaten - damit werden Entfernungen im projizierten Raum genau gemessen, jedoch nicht geografisch (z. B. WGS-1984).
SCW
4

Sie können auch die Längeneigenschaft von Shapely verwenden , dh:

from shapely.wkt import loads

l=loads('LINESTRING(3.0 4.0, 3.1 4.1)')
print l.length
tomkralidis
quelle
Beachten Sie, dass die Länge für dieses Beispiel bedeutungslos ist, da es sich um ein geografisches Koordinatensystem handelt (WGS84).
Mike T
2

Spät zur Party, aber mit einem hoffentlich nützlichen Beitrag. Aufbauend auf der Antwort von scw mit Hilfe von Geopy habe ich eine kleine Funktion geschrieben, die die Berechnung für ein formschönes LineString-Objekt mit beliebig vielen Koordinaten durchführt. Es wird ein pairsIterator von Stackoverflow verwendet.

Hauptmerkmal: Die Docstrings sind viel länger als die Snippets.

def line_length(line):
    """Calculate length of a line in meters, given in geographic coordinates.
    Args:
        line: a shapely LineString object with WGS 84 coordinates
    Returns:
        Length of line in meters
    """
    # Swap shapely (lonlat) to geopy (latlon) points
    latlon = lambda lonlat: (lonlat[1], lonlat[0])
    total_length = sum(distance(latlon(a), latlon(b)).meters
                       for (a, b) in pairs(line.coords))
    return round(total_length, 0)


def pairs(lst):
    """Iterate over a list in overlapping pairs without wrap-around.

    Args:
        lst: an iterable/list

    Returns:
        Yields a pair of consecutive elements (lst[k], lst[k+1]) of lst. Last 
        call yields the last two elements.

    Example:
        lst = [4, 7, 11, 2]
        pairs(lst) yields (4, 7), (7, 11), (11, 2)

    Source:
        /programming/1257413/1257446#1257446
    """
    i = iter(lst)
    prev = i.next()
    for item in i:
        yield prev, item
        prev = item
ojdo
quelle
1
Dies ist falsch: geopy.distance.distance akzeptiert Koordinaten in (y, x), aber eine formschöne Linienfolge ist "eine geordnete Folge von 2 oder mehr (x, y [, z])", daher muss die Hilfsfunktion lonlat () von geopy verwendet werden .
Martin Burch
@MartinBurch: autsch, du hast recht. Das Schlimme ist nicht einmal das [, z], aber das Argument (y, x)dafür (x, y)ist notwendig. Danke, dass du es gesehen hast. Kannst du gucken, ob diese Bearbeitung weniger fehlerhaft aussieht?
Ojdo