Calculating geographic distance between a list of

2019-07-13 14:27发布

问题:

I'm writing a flask application, using some data extracted from a GPS sensor. I am able to draw the route on a Map and I want to calculate the distance the GPS sensor traveled. One way could be to just get the start and end coordinates, however due to the way the sensor travels this is quite inaccurate. Therefore I do sampling of each 50 sensor samples. If the real sensor sample size was 1000 I will now have 20 samples (by extracting each 50 sample).

Now I want to be able to put my list of samples through a function to calculate distance. So far I've been able to use the package geopy, but when I take large gps sample sets I do get "too many requests" errors, not to mention I will have extra processing time from processing the requests, which is not what I want.

Is there a better approach to calculating the cumulative distance of a list element containing latitude and longitude coordinates?

positions = [(lat_1, lng_1), (lat_2, lng_2), ..., (lat_n, lng_n)]

I found methods for lots of different mathematical ways of calculating distance using just 2 coordinates (lat1, lng1 and lat2 and lng2), but none supporting a list of coordinates.

Here's my current code using geopy:

from geopy.distance import vincenty

def calculate_distances(trips):
    temp = {}
    distance = 0
    for trip in trips:
        positions = trip['positions']
        for i in range(1, len(positions)):
            distance += ((vincenty(positions[i-1], positions[i]).meters) / 1000)
            if i == len(positions):
                temp = {'distance': distance}
                trip.update(temp)
                distance = 0

trips is a list element containing dictionaries of key-value pairs of information about a trip (duration, distance, start and stop coordinates and so forth) and the positions object inside trips is a list of tuple coordinates as visualized above.

trips = [{data_1}, {data_2}, ..., {data_n}]

回答1:

I'd recommend transform your (x, y) coordinates into complex, as it is computational much easier to calculate distances. Thus, the following function should work:

def calculate_distances(trips):
    for trip in trips:
        positions = trip['positions']
        c_pos = [complex(c[0],c[1]) for c in positions]
        distance = 0
        for i in range(1, len(c_pos)):
            distance += abs(c_pos[i] - c_pos[i-1])
        trip.update({'distance': distance})

What I'm doing is converting every (lat_1, lng_1) touple into a single complex number c1 = lat_1 + j*lng_1, and creates a list formed by [c1, c2, ... , cn].

A complex number is, all in all, a 2-dimensional number and, therefore, you can make this if you have 2D coordinates, which is perfect for geolocalization, but wouldn't be possible for 3D space coordinates, for instance.

Once you got this, you can easily compute the distance between two complex numbers c1 and c2 as dist12 = abs(c2 - c1). Doing this recursively you obtain the total distance.

Hope this helped!



回答2:

Here's the solution I ended up using. It's called the Haversine (distance) function if you want to look up what it does for yourself.

I changed my approach a little as well. My input (positions) is a list of tuple coordinates:

def calculate_distance(positions):
    results = []
    for i in range(1, len(positions)):
        loc1 = positions[i - 1]
        loc2 = positions[i]

        lat1 = loc1[0]
        lng1 = loc1[1]

        lat2 = loc2[0]
        lng2 = loc2[1]

        degreesToRadians = (math.pi / 180)
        latrad1 = lat1 * degreesToRadians
        latrad2 = lat2 * degreesToRadians
        dlat = (lat2 - lat1) * degreesToRadians
        dlng = (lng2 - lng1) * degreesToRadians

        a = math.sin(dlat / 2) * math.sin(dlat / 2) + math.cos(latrad1) * \
        math.cos(latrad2) * math.sin(dlng / 2) * math.sin(dlng / 2)
        c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
        r = 6371000

        results.append(r * c)

    return (sum(results) / 1000)  # Converting from m to km