Python - понижающая дискретизация списка точек с заданными координатами и расстоянием между двумя соседними точками в списке
Я действительно надеюсь, что кто-то может помочь мне с этим! Я пытаюсь заставить этот скрипт работать так, как я хочу, но я не могу понять, как это работает.
Файл с данными для обработки вводится с GPS и выглядит следующим образом:
Line 20081002-1119.nmea
$GPGGA,094406.00,5849.40174,N,01738.15828,E,2,08,00.9,00003.26,M,0024.93,M,005,0734*62
$GPGGA,094407.00,5849.40177,N,01738.15827,E,2,08,00.9,00003.22,M,0024.93,M,005,0734*6B
$GPGGA,094408.00,5849.40174,N,01738.15826,E,2,08,00.9,00003.00,M,0024.93,M,006,0734*65
$GPGGA,094409.00,5849.40171,N,01738.15831,E,2,08,00.9,00003.24,M,0024.93,M,005,0734*62
$GPGGA,094410.00,5849.40176,N,01738.15833,E,2,08,00.9,00003.29,M,0024.93,M,006,0734*61
$GPGGA,094411.00,5849.40172,N,01738.15831,E,2,08,00.9,00003.31,M,0024.93,M,004,0734*6D
$GPGGA,094412.00,5849.40172,N,01738.15830,E,2,08,00.9,00003.15,M,0024.93,M,005,0734*68
$GPGGA,094413.00,5849.40175,N,01738.15834,E,2,08,00.9,00003.18,M,0024.93,M,005,0734*67
$GPGGA,094414.00,5849.40173,N,01738.15835,E,2,08,00.9,00003.16,M,0024.93,M,006,0734*6A
EOL
Мой выходной файл должен выглядеть следующим образом (теперь с размеченными расстояниями, чтобы показать, что я хочу):
Line 20081002-1119.nmea
58.853952 17.643113 102.15
58.853946 17.643243 101.63
58.853939 17.643372 105.93
58.853933 17.643503 104.01
58.853927 17.643633 104.25
...
EOL
Столбцы: долгота, широта, расстояние до точки выше.
Как мне сделать, чтобы уменьшить частоту дискретизации до заданного интервала между двумя точками (в моем случае 100 метров)?
Сценарий, который я выполнил до сих пор: `
indata=open('C:/nav.nmea', 'r')
outdata=open('C:/nav_out.txt', 'w')
from math import *
coords_list=[]
coords=[]
def distance(coords_list):
for (longi2,lati2) in coords_list:
for (longi1,lati1) in coords_list:
a = sin(lati1) * sin(lati2)+cos(longi1-longi2)*cos(lati1) * cos(lati2)
c= 2* asin(sqrt(a))
s= (6367* c)/100000 # For results in meters
if s<100:
# Here I want to discard current line if not s<100 and jump to the next line
else:
"Return the valid lines"
return s
for line in indata:
if line.startswith('$GPGGA'):
data=line.split(",")
# Import only coordinates from input file
LON=float(data[2])/100
LAT=float(data[4])/100
# Convert coordinates from DDMM.MMMM to DD.DDDDDD
lon=((LON-int(LON))/60)*100+int(LON)
lat=((LAT-int(LAT))/60)*100+int(LAT)
coords_list.append((lon,lat))
outdata.writelines("%0.6f\t" %lon)
outdata.writelines("%0.6f\t" %lat)
outdata.writelines("%s \n" %distance(coords_list))
elif line.startswith('EOL'):
outdata.writelines("EOL")
elif line.startswith('Line'):
LineID=line
outdata.writelines('\n%s' %LineID)
indata.close()
outdata.close()
`
3 ответа
Для уменьшения точки на кривой вы, вероятно, захотите использовать алгоритм Рамера-Дугласа-Пекера. Это сохраняет общую форму кривой, но удаляет детали, количество удаляемой может контролироваться параметром.
Обратите внимание, что код на связанной странице Википедии - псевдокод, а не python.
Я нашел Python-реализацию алгоритма упрощения строк DP, я не проверял его и не могу ручаться за его правильность.
Вот довольно простой способ уменьшить данные: coord1
используется для хранения предыдущей координаты. Каждый раз, когда через цикл, расстояние между coord1
и новая координата, coord2
, вычисляется. Когда расстояние <100, остальная часть цикла пропускается.
import math
import itertools
def distance(coord1,coord2):
longi1,lati1=coord1
longi2,lati2=coord2
a = (math.sin(lati1)*math.sin(lati2)
+math.cos(longi1-longi2)*math.cos(lati1)*math.cos(lati2))
c = 2*math.asin(math.sqrt(a))
s = (6367*c)/100000 # For results in meters
return s
with open('nav.nmea', 'r') as indata:
with open('nav_out.txt', 'w') as outdata:
coords=[]
coord1=None
for line in indata:
if line.startswith('$GPGGA'):
data=line.split(",")
# Import only coordinates from input file
LON=float(data[2])/100
LAT=float(data[4])/100
# Convert coordinates from DDMM.MMMM to DD.DDDDDD
lon=((LON-int(LON))/60)*100+int(LON)
lat=((LAT-int(LAT))/60)*100+int(LAT)
coords.append((lon,lat))
if coord1 is None:
# The first time through the loop `coord1` is None
outdata.write('%0.6f\t%0.6f\t%s \n'%(lon,lat,0))
coord1=(lon,lat)
else:
coord2=(lon,lat)
dist=distance(coord1,coord2)
if dist<100:
# go back to the beginning of the loop
continue
outdata.write('%0.6f\t%0.6f\t%s \n'%(lon,lat,dist))
coord1=coord2
elif line.startswith('EOL'):
outdata.writelines("EOL")
elif line.startswith('Line'):
LineID=line
outdata.writelines('\n%s' %LineID)
def generate_survexpath(points, tz=None, distance=10):
"""Generate a survey path from a list of points.
The survey path will consist of a series of points spaced at a given distance = 10 metres.
This has to cope with interpolating new points,
but also skipping existing points if they are too close.
"""
survexpath = []
i = 0
while i < len(points) - 2:
i = i + 1
p1 = points[i]
j = i + 1
p2 = points[j]
# Calculate the distance between successive points.
distance_between_points = calculate_distance(p1, p2)
# Calculate the number of points to include in the survey path between the two points.
num_points = int(distance_between_points / distance)
# Step through the track until the gap is > 10m
while num_points == 0 and j < len(points) - 1:
j = j + 1
p2 = points[j]
distance_between_points = calculate_distance(p1, p2)
num_points = int(distance_between_points / distance)
# re set the start point for looking for a gap > 10m
i = j
# Generate the survey path points where the gap is > 10m
if num_points > 0:
for k in range(num_points + 1):
t = k / num_points
lat = p1.lat + (p2.lat - p1.lat) * t
lon = p1.lon + (p2.lon - p1.lon) * t
ele = p1.ele + (p2.ele - p1.ele) * t
time =""
if k == 0 and p1.time:
time = p1.time.astimezone(tz=tz)
p = Point(lat, lon, ele, name=f"{i}-{k}", time=time)
survexpath.append(p)
if points:
# file may have no trkpts, only waypoints
last = points[-1]
if not last.name:
last.name = len(points)
if last.time:
last.time =last.time.astimezone(tz=tz)
survexpath.append(last) # and the last one anyway.
return survexpath
"""Для GPX, а не для NMEA, но логика та же. Это и понижающая, и повышающая дискретизация, так что все ветки составляют примерно 10 метров.
Полный код на https://expo.survex.com/repositories/loser/.git/tree/gpx/gpx2survex.py"""