Recherche d'un moyen pythonique pour calculer la longueur d'une chaîne WKT


13

Je n'étais pas du tout satisfait du calcul de la longueur des chaînes linéaires en WGS84 en miles . Cela m'a incité à me demander s'il existe un moyen Pythonique plus pratique de calculer la longueur d'une chaîne de caractères WKT en fonction d'un SRID donné.

Je pense à quelque chose comme:

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

Je cherche une réponse précise, pas des sin\cosapproximations.

Des idées?


tomkralidis, il s'agit d'un site Web SIG. votre réponse ignore que c'est une distance entre les coordonnées géospatiales (recherchez SRID). galbée en soi ne peut pas calculer les distances géospatiales car elle n'a aucune connaissance de la projection cartographique.

Réponses:


18

Le module geopy fournit la formule Vincenty , qui fournit des distances ellipsoïdes précises. wktAjoutez ceci au chargement dans Shapely, et vous avez un code assez simple:

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, aurait +10 si je le pouvais. J'ai sauvé les heures de programmation de mon équipe.
Adam Matan

Cette approche est-elle différente de la réponse de @tomkralidis si les coordonnées d'entrée sont déjà dans WGS-84?
LarsVegas

1
@LarsVegas oui, Shapely ne gère que les coordonnées planes - il mesurera donc les distances avec précision dans l'espace projeté, mais pas géographique (par exemple WGS-1984).
scw

4

Vous pouvez également utiliser la propriété length de Shapely , c'est-à-dire:

from shapely.wkt import loads

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

Notez que la longueur de cet exemple particulier n'aura aucun sens, car il s'agit d'un système de coordonnées géographiques (WGS84).
Mike T


2

Tard dans la soirée, mais avec une contribution si tout va bien utile. En s'appuyant sur la réponse de scw en utilisant geopy, j'ai écrit une petite fonction qui fait le calcul pour un objet LineString galbé avec arbitrairement de nombreuses coordonnées. Il utilise un pairsitérateur de Stackoverflow.

Caractéristique principale: les docstrings sont beaucoup plus longs que les extraits.

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
C'est faux: geopy.distance.distance accepte les coordonnées en (y, x) mais une chaîne de lignes bien faite est "une séquence ordonnée de 2 ou plus (x, y [, z])" donc la fonction d'aide de geopy lonlat () doit être utilisée .
Martin Burch

@MartinBurch: aïe, vous avez raison. La chose est méchant même pas [, z], mais l'échange d'arguments (y, x)à (x, y)ce qui est nécessaire. Merci de l'avoir repéré. Pouvez-vous savoir si cette modification semble moins parasitée?
ojdo
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.