Poszukuje pytonowego sposobu obliczenia długości oznaczenia linii WKT

13

Byłem bardzo niezadowolony z obliczania długości pościeli w WGS84 w Milach . Zastanawiałem się, czy istnieje wygodniejszy, Pythoński sposób obliczania długości linii WKT zgodnie z danym SRID.

Mam na myśli coś takiego:

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

Szukam dokładnej odpowiedzi, a nie sin\cosprzybliżeń.

Jakieś pomysły?

Adam Matan
źródło
tomkralidis, to jest strona GIS. twoja odpowiedź ignoruje, że jest to odległość między współrzędnymi geoprzestrzennymi (patrz SRID). kształtny sam w sobie nie może obliczyć odległości geoprzestrzennych, ponieważ nie ma wiedzy na temat rzutowania mapy.

Odpowiedzi:

18

Geopy moduł stanowi wzór Wincenty , który zapewnia dokładne odległości elipsoidy. Połącz to z wktładowaniem w Shapely, a masz dość prosty kod:

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
źródło
1
+1, miałbym +10, gdybym mógł. Zaoszczędziłem godzinom programowania mojego zespołu.
Adam Matan,
Czy to podejście różni się od odpowiedzi @tomkralidis, jeśli współrzędne wejściowe są już w WGS-84?
LarsVegas,
1
@ LarsVegas tak, Shapely obsługuje tylko współrzędne planarne - więc dokładnie mierzy odległości w rzutowanej przestrzeni, ale nie geograficznie (np. WGS-1984).
scw
4

Możesz także użyć właściwości długości Shapely , tj .:

from shapely.wkt import loads

l=loads('LINESTRING(3.0 4.0, 3.1 4.1)')
print l.length
tomkralidis
źródło
Pamiętaj, że długość tego konkretnego przykładu będzie bez znaczenia, ponieważ jest to układ współrzędnych geograficznych (WGS84).
Mike T
2

Późno na imprezę, ale z nadzieją użyteczną pomocą. Opierając się na odpowiedzi scw za pomocą geopoli, napisałem małą funkcję, która wykonuje obliczenia dla foremnego obiektu LineString o dowolnie wielu współrzędnych. Używa pairsiteratora z Stackoverflow.

Główna cecha: dokumenty są znacznie dłuższe niż fragmenty.

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
źródło
1
To źle: geopy.distance.distance akceptuje współrzędne w (y, x), ale foremne oznaczenie linii to „uporządkowana sekwencja 2 lub więcej (x, y [, z])”, więc należy użyć funkcji pomocniczej geopoli lonlat () .
Martin Burch,
@MartinBurch: ouch, masz rację. Paskudny rzeczą nie jest nawet [, z], ale swap argumentem (y, x)na (x, y)to jest konieczne. Dzięki za wykrycie tego. Czy potrafisz spojrzeć, czy ta edycja wygląda mniej na błędy?
ojdo