Шукаєте пітонічний спосіб розрахунку довжини рядка WKT


13

Я був незадоволений обчисленням довжини рядків у WGS84 в милях . Мене змусило замислитися, чи існує більш зручний, пітонічний спосіб обчислити довжину рядків WKT відповідно до заданої SRID.

Я маю на увазі щось на кшталт:

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

Я шукаю точну відповідь, а не sin\cosнаближення.

Будь-які ідеї?


tomkralidis, це веб-сайт ГІС. Ваша відповідь ігнорує, що це відстань між геопросторовими координатами (шукайте SRID). формально сам по собі не може обчислити геопросторові відстані, оскільки не має знань про проекцію карти.

Відповіді:


18

Модуль геопії забезпечує формулу Вінсенті , яка забезпечує точні еліпсоїдальні відстані. З'єднайте це з wktзавантаженням у Shapely, і у вас досить простий код:

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, мав би +10, якби міг. Зберегли мою команду годин програмування.
Адам Матан

Чи відрізняється цей підхід від відповіді @tomkralidis, якщо вхідні координати вже є у WGS-84?
LarsVegas

1
@LarsVegas так, Shapely обробляє лише плоскі координати - тому він буде точно вимірювати відстані в прогнозованому просторі, але не географічні (наприклад, WGS-1984).
scw

4

Ви також можете використовувати властивість довжини Shapely , тобто:

from shapely.wkt import loads

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

Зауважте, що довжина для цього конкретного прикладу буде безглуздою, оскільки це географічна система координат (WGS84).
Майк Т


2

Пізно на вечірку, але з надією корисним внеском. Спираючись на відповідь Scw за допомогою геопії, я написав невелику функцію, яка виконує обчислення для стрункого об’єкта LineString з довільно багатьма координатами. Він використовує pairsітератор від Stackoverflow.

Основна особливість: docstrings набагато довші, ніж фрагменти.

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
Це неправильно: geopy.distance.distance приймає координати в (y, x), але струнка лінія рядка - це "впорядкована послідовність 2 або більше (x, y [, z])", тому функція помічника geopy lonlat () повинна бути використана .
Мартін Берч

@MartinBurch: ой, ти маєш рацію. Гидоти навіть не [, z], але аргумент своп (y, x)на (x, y)те , що потрібно. Дякуємо, що помітили його. Чи можете ви зробити очне яблуко, чи виглядає ця редакція менш помилкою?
ойдо
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.