Alla ricerca di un modo pitonico per calcolare la lunghezza di una stringa lineare WKT


13

Non ero abbastanza soddisfatto del calcolo della lunghezza dei linestring in WGS84 in miglia . Mi ha fatto domandare se esiste un modo più conveniente, Pythonic per calcolare la lunghezza di una stringa lineare WKT secondo un dato SRID.

Ho in mente qualcosa come:

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

Sto cercando una risposta accurata, non sin\cosapprossimazioni.

Qualche idea?


tomkralidis, questo è un sito GIS. la tua risposta ignora che questa è una distanza tra coordinate geospaziali (cerca SRID). formalmente in sé non può calcolare le distanze geospaziali in quanto non ha conoscenza della proiezione cartografica.

Risposte:


18

Il modulo geopy fornisce la formula Vincenty , che fornisce precise distanze ellissoidali. Abbina questo al wktcaricamento in Shapely e hai un codice ragionevolmente semplice:

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

1
+1, avrei +10 se potessi. Ho risparmiato ore di programmazione al mio team.
Adam Matan,

Questo approccio è diverso dalla risposta di @tomkralidis se le coordinate di input sono già in WGS-84?
LarsVegas,

1
@LarsVegas sì, Shapely gestisce solo le coordinate planari, quindi misurerà accuratamente le distanze nello spazio proiettato, ma non geografico (ad es. WGS-1984).
scw,

4

Puoi anche usare la proprietà length di Shapely , ovvero:

from shapely.wkt import loads

l=loads('LINESTRING(3.0 4.0, 3.1 4.1)')
print l.length

Si noti che la lunghezza di questo particolare esempio non avrà senso, poiché si tratta di un sistema di coordinate geografiche (WGS84).
Mike T


2

In ritardo alla festa, ma con un contributo speriamo utile. Sulla base di scw risposta utilizzando geopy, ho scritto una piccola funzione che fa il calcolo di un oggetto LineString formosa con un numero arbitrario di coordinate. Utilizza un pairsiteratore da StackOverflow.

Caratteristica principale: le dotstring sono molto più lunghe degli snippet.

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

1
Questo è sbagliato: geopy.distance.distance accetta le coordinate in (y, x) ma una stringa lineare ben definita è "una sequenza ordinata di 2 o più (x, y [, z])", quindi è necessario utilizzare la funzione di supporto della geopy lonlat () .
Martin Burch,

@MartinBurch: ahi, hai ragione. La cosa brutta non è nemmeno il [, z], ma lo swap tesi (y, x)a (x, y)ciò che è necessario. Grazie per averlo individuato. Riesci a capire se questa modifica sembra meno infestata da bug?
ojdo,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.