¿Qué es la unidad de atributo de longitud bien proporcionada?

11

Estoy haciendo un cálculo muy simple de la longitud de una polilínea usando bien:

from shapely.geometry import LineString
... 
xy_list = [map(float,e) for e in xy_intm]
line = LineString(xy_list)
s = '%s,%s,%s' % (fr,to,line.length)

Mis coordenadas están en WGS84. Parece que no puedo encontrar ninguna información sobre el atributo de longitud de Shapely. ¿Cuál es la unidad del atributo de longitud? ¿Hay una manera fácil de convertir a km o metros?

LarsVegas
fuente
¿Puedes proporcionar las coordenadas y la longitud de dos formas de muestra?
Vince

Respuestas:

13

Como dice alfaciano en forma, la distancia es la distancia euclidiana o la distancia lineal entre dos puntos en un plano y no la distancia del gran círculo entre dos puntos en una esfera.

from shapely.geometry import Point
import math


point1 = Point(50.67,4.62)
point2 = Point(51.67, 4.64)

# Euclidean Distance
def Euclidean_distance(point1,point2):
     return math.sqrt((point2.x()-point1.x())**2 + (point2.y()-point1.y())**2)

print Euclidean_distance(point1,point2)
1.00019998 # distance in degrees (coordinates of the points in degrees)

# with Shapely
print point1.distance(point2)
1.0001999800039989 #distance in degrees (coordinates of the points in degrees)

Para la distancia del gran círculo, debe usar algoritmos como la ley de los cosenos o la fórmula de Haversine (vea ¿Por qué la ley de los cosenos es más preferible que la haversine al calcular la distancia entre dos puntos de latitud y longitud? ) O use el módulo pyproj que realiza cálculos geodésicos.

# law of cosines
distance = math.acos(math.sin(math.radians(point1.y))*math.sin(math.radians(point2.y))+math.cos(math.radians(point1.y))*math.cos(math.radians(point2.y))*math.cos(math.radians(point2.x)-math.radians(point1.x)))*6371
print "{0:8.4f}".format(distance)
110.8544 # in km
# Haversine formula
dLat = math.radians(point2.y) - math.radians(point1.y)
dLon = math.radians(point2.x) - math.radians(point1.x)
a = math.sin(dLat/2) * math.sin(dLat/2) + math.cos(math.radians(point1.y)) * math.cos(math.radians(point2.y)) * math.sin(dLon/2) * math.sin(dLon/2)
distance = 6371 * 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
print "{0:8.4f}".format(distance)distance
110.8544 #in km

# with pyproj
import pyproj
geod = pyproj.Geod(ellps='WGS84')
angle1,angle2,distance = geod.inv(point1.x, point1.y, point2.x, point2.y)
print "{0:8.4f}".format(distance/1000)
110.9807 #in km

Puede probar el resultado en la Calculadora de distancia de latitud y longitud

ingrese la descripción de la imagen aquí

gene
fuente
Gran respuesta, Gene! Muchas gracias por tu explicación muy detallada.
Antonio Falciano
1
De hecho, gran respuesta. Si no me equivoco, hay otro paquete de Python llamado geopyque ha implementado un cálculo de distancia de gran círculo y distancia de Vincenty.
LarsVegas
Aquí hay algunos detalles sobre el cálculo de distancia geodésica con geopy.
Antonio Falciano
13

Sistemas coordinados

[...] Shapely no admite transformaciones de sistemas de coordenadas. Todas las operaciones en dos o más entidades suponen que las entidades existen en el mismo plano cartesiano.

Fuente: http://toblerity.org/shapely/manual.html#coordinate-systems

Siendo shapelycompletamente agnóstico en referencia a SRS, es bastante obvio que el atributo de longitud se expresa en la misma unidad de coordenadas de su cadena lineal, es decir, grados. De hecho:

>>> from shapely.geometry import LineString
>>> line = LineString([(0, 0), (1, 1)])
>>> line.length
1.4142135623730951

En cambio, si desea expresar la longitud en metros, debe transformar sus geometrías de WGS84 a un SRS proyectado utilizando pyproj (o, mejor, ejecutar el cálculo de distancia geodésica, consulte la respuesta de Gene). En detalle, desde la versión 1.2.18 ( shapely.__version__), shapelyadmite las funciones de transformación de geometría ( http://toblerity.org/shapely/shapely.html#module-shapely.ops ) con las que podemos usarlo junto con pyproj. Aquí hay un ejemplo rápido:

from shapely.geometry import LineString
from shapely.ops import transform
from functools import partial
import pyproj

line1 = LineString([(15.799406, 40.636069), (15.810173,40.640246)])
print str(line1.length) + " degrees"
# 0.0115488362184 degrees

# Geometry transform function based on pyproj.transform
project = partial(
    pyproj.transform,
    pyproj.Proj(init='EPSG:4326'),
    pyproj.Proj(init='EPSG:32633'))

line2 = transform(project, line1)
print str(line2.length) + " meters"
# 1021.77585965 meters
Antonio Falciano
fuente