Volto a esse problema porque é muito semelhante a Como encontro o rolamento de linhas vetoriais no QGIS ou GRASS? e pode ser resolvido com o Python da mesma maneira:
1) Distância de Haversine
Pode-se encontrar muitos scripts pesquisando a distância de Haversine com Python na Internet e eu escolho um deles na fórmula de Haversine em Python (rolamento e distância entre dois pontos de GPS)
def haversine(lon1, lat1, lon2, lat2):
"""
Calculate the great circle distance between two points
on the earth (specified in decimal degrees)
"""
# convert decimal degrees to radians
lon1, lat1, lon2, lat2 = map(math.radians, [lon1, lat1, lon2, lat2])
# haversine formula
dlon = lon2 - lon1
dlat = lat2 - lat1
a = math.sin(dlat/2)**2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon/2)**2
c = 2 * math.asin(math.sqrt(a))
km = 6367 * c
return km
Temos uma série de linhas (pontos) no arquivo que devem ser tratadas em pares (ponto1 - ponto2) para calcular a distância. Para isso, usaremos um iterador simples da maneira Most pythonic para obter o elemento anterior
def offset(iterable):
prev = None
for elem in iterable:
yield prev, elem
prev = elem
Agora é possível ler o arquivo (exemplo de Kerrie) em pares de linhas / pontos
import csv
with open('testhavers.csv', 'rb') as f:
reader = csv.DictReader(f)
for pair in offset(reader):
print pair
(None, {'LAT': '10.08527', 'LON': '124.59833', 'ID': '1', 'TIME': '21:24:37'})
({'LAT': '10.08527', 'LON': '124.59833', 'ID': '1', 'TIME': '21:24:37'},
{'LAT': '10.08523', 'LON': '124.59830', 'ID': '2', 'TIME': '21:25:07'})
({'LAT': '10.08523', 'LON': '124.59830', 'ID': '2', 'TIME': '21:25:07'},
{'LAT': '10.08526', 'LON': '124.59832', 'ID': '3', 'TIME': '21:25:37'})
({'LAT': '10.08526', 'LON': '124.59832', 'ID': '3', 'TIME': '21:25:37'},
{'LAT': '10.08526', 'LON': '124.59831', 'ID': '4', 'TIME': '21:26:07'})
Em seguida, crie um shapefile contendo os campos originais do arquivo csv e um novo campo para a distância com os módulos Python Shapely e Fiona de Sean Gillies:
import fiona
from shapely.geometry import Point, mapping
# creation of the schema of the shapefile (geometry and fields)
schema = { 'geometry': 'Point', 'properties':{'ID': 'int', 'LAT':'float', 'LON':'float', 'TIME':'str','distance' : 'float'}}
# creation of the shapefile:
with fiona.collection("result.shp", "w", "ESRI Shapefile", schema) as output:
# reading the csv file
with open('testhavers.csv', 'rb') as f:
reader = csv.DictReader(f)
# we need here to eliminate the first pair of point with None
for i, pair in enumerate(offset(reader)):
if i == 0: (pair with None)
# writing of the point geometry and the attributes
point = Point(float(pair[1]['LON']), float(pair[1]['LAT']))
dist = 0 # None
output.write({'properties': {'ID':int(pair[1]['ID']),'LAT':float(pair[1]['LAT']),'LON':float(pair[1]['LON']), 'TIME':pair[1]['TIME'],'distance': dist},'geometry': mapping(point)})
else:
# writing of the point geometry and the attributes
point = Point(float(pair[1]['LON']), float(pair[1]['LAT']))
# Haversine distance between pairs of points
dist = haversine(float(pair[0]['LON']), float(pair[0]['LAT']), float(pair[1]['LON']),float(pair[1]['LAT']))
output.write({'properties': {'ID':int(pair[1]['ID']),'LAT':float(pair[1]['LAT']),'LON':float(pair[1]['LON']), 'TIME':pair[1]['TIME'],'distance': dist},'geometry': mapping(point)})
e o resultado:
Também é possível fazer isso com o PyQGIS, mas é mais complexo que o Fiona, que usa dicionários simples para criar shapefiles.
Você pode usar outra função para calcular a distância de Haversine ( por que a lei dos cossenos é mais preferível do que a haversine ao calcular a distância entre dois pontos de latitude-longitude? ) Sem nenhum problema, apenas o cálculo da distância muda, não o processo de criação do shapefile.