From cb075ec78f3d816f9688cfd7d3cb7f8d960832e7 Mon Sep 17 00:00:00 2001 From: itsGarrin Date: Wed, 8 Nov 2023 18:08:06 -0500 Subject: Changed types for router.py --- dashboard_website/router.py | 117 ++++++++++++++++++++------------------------ 1 file changed, 52 insertions(+), 65 deletions(-) diff --git a/dashboard_website/router.py b/dashboard_website/router.py index 658c112..709c8d1 100644 --- a/dashboard_website/router.py +++ b/dashboard_website/router.py @@ -3,7 +3,10 @@ import pandas as pd import requests from sklearn.cluster import KMeans -host = "http://acetyl.net:5000" # queries acetyl.net:5000, the OSRM engine +from dashboard_website import db + +host = "http://acetyl.net:5000" # queries acetyl.net:5000, the OSRM engine + # external facing functions @@ -14,113 +17,94 @@ def getRouteFullJSON(bike, clue): r = response.get(url) return r.json() + def getRouteHDPolyline(bike, clue): url = f"{host}/route/v1/bike/{bike['longitude']},{bike['latitude']};{clue['longitude']},{clue['latitude']}?overview=full&geometries=geojson" r = response.get(url) p = r.json()['trips'][0]['geometry']['coordinates'] return p + def getRouteFastPolyline(bike, clue): url = f"{host}/route/v1/bike/{bike['longitude']},{bike['latitude']};{clue['longitude']},{clue['latitude']}?geometries=geojson" r = response.get(url) p = r.json()['trips'][0]['geometry']['coordinates'] return p + def getZSP(bike, home, clue_cluster): pass + # determines clusters based on current bikes and clues def getClusters(bikes, clues, endpoint): - clusters = [ [] for bike in bikes ] + clusters = [[] for bike in bikes] active_bikes = [bike for bike in bikes if bike.status == "ACTIVE"] active_clues = [clue for clue in clues if clue.status == "UNVISITED"] # select only active bikes # select only unvisited clues - clusters_t, route_geo = cluster_and_optimize( active_clues, active_bikes,endpoint) + clusters_t, route_geo = cluster_and_optimize(active_clues, active_bikes, endpoint) for cluster in clusters_t: clusters[i] = cluster - #return list of clue clusters corresponding to bikes + # return list of clue clusters corresponding to bikes pass + # utility functions (internal) -def cluster_and_optimize(df, centroids, end, time_diff=0.25, max_time=24, n=2): +def cluster_and_optimize(clues: [db.Clue], bikes: [db.Bike], end: db.Point, time_diff=0.25, max_time=24, n=2): """ Takes a dataframe of gps coordinates, a list of centroids, and an end point and returns a dataframe with a cluster - :param df: a dataframe of gps coordinates - :param centroids: a list of centroids + :param clues: a list of clues + :param bikes: a list of centroids :param end: the end point of the trip :param time_diff: the maximum time difference between the longest trip and the average trip :param max_time: the maximum time of the trip :param n: the number of routes to create :return: a dataframe with a cluster column """ + regular_points = [] + for clue in clues: + regular_points.append(db.Point(clue.latitude, clue.longitude)) + # Create a new column with normalized gps coordinates and centroids - df['normalized_gps'], norm_centroids = __normalize_gps(df['gps'].values.tolist(), centroids) + normalized_points, norm_centroids = __normalize_points([db.Point(clue.latitude, clue.longitude) for clue in clues], + [db.Point(bike.latitude, bike.longitude) for bike in bikes]) # Cluster the coordinates kmeans = KMeans(n_clusters=len(norm_centroids), init=norm_centroids) - kmeans.fit(df['normalized_gps'].values.tolist()) + kmeans.fit(normalized_points) - df['cluster'] = kmeans.labels_ + # Create a dataframe with the gps coordinates, the cluster, and the list of coordinates + df = pd.DataFrame({'gps': regular_points, 'cluster': kmeans.labels_}) + # Create the coordinate list from the bikes (the centroids) and the routes (the clues) routes = [] - starts = [] - for i in range(len(centroids)): - routes.append(df[df['cluster'] == i]['gps'].values.tolist()) - starts.append(list_to_string([centroids[i]])) + for i in range(len(bikes)): + routes.append(df[df['cluster'] == i]['gps'].tolist()) - routes = __minimize_route_time_diff(routes, starts, end, time_diff, n) + routes = __minimize_route_time_diff(routes, bikes, end, time_diff, n) # Remove waypoints from the longest route until the trip time is less than the max time for i in range(len(routes)): - routes[i] = __remove_longest_waypoints(routes[i], starts[i], end, max_time) + routes[i] = __remove_longest_waypoints(routes[i], bikes[i], end, max_time) df.loc[df['gps'].astype(str).isin(map(str, routes[i])), 'cluster'] = i - return df, routes - -def list_to_string(list_of_lists): +def __points_to_string(point: [db.Point]): """ - Takes a list of lists and returns a string of the list of lists - :param list_of_lists: a list of lists - :return: a string of the list of lists + Takes a list of points and returns a string of the list of points + :param point: a list of points + :return: a string of the list of points """ string = '' - for i in list_of_lists: - string += str(i[1]) + ',' + str(i[0]) + ';' + for i in point: + string += str(i.longitude) + ',' + str(i.latitude) + ';' return string -def create_json_df(coordinate_string, start, end): - """ - Takes a string of coordinates and returns a dataframe of the coordinates in order of the waypoint index - :param coordinate_string: a string of coordinates - :param start: the start point of the trip - :param end: the end point of the trip - :return: a dataframe of the coordinates in order of the waypoint index - """ - coordinates = requests.get( - 'http://acetyl.net:5000/trip/v1/bike/' + start + coordinate_string + end + '?roundtrip=false&source=first&destination=last') - coordinates = coordinates.json() - - # Create a dataframe from the JSON - df = pd.DataFrame(coordinates['waypoints']) - - # Separate the location column into lon and lat columns - df['lat'] = df['location'].apply(lambda x: x[0]) - df['lon'] = df['location'].apply(lambda x: x[1]) - - df['waypoint_index'] = df['waypoint_index'].astype(int) - - # Map out the waypoints in order of the waypoint index - df = df.sort_values(by=['waypoint_index']) - - return df - - -def get_trip_time(coordinate_string, num_waypoints, start, end, time_per_waypoint=90): +def __get_trip_time(coordinate_string, num_waypoints, start, end, time_per_waypoint=90): """ Takes a string of coordinates and returns the trip time in hours :param coordinate_string: a string of coordinates @@ -142,7 +126,7 @@ def get_trip_time(coordinate_string, num_waypoints, start, end, time_per_waypoin return total_time_hours -def __minimize_route_time_diff(routes, starts, end, time_diff, n): +def __minimize_route_time_diff(routes: [db.Point], starts: [db.Point], end: db.Point, time_diff, n): """ Takes a list of lists of coordinates, a list of start points, an end point, a time difference, and a number of routes :param routes: the list of lists of coordinates @@ -155,7 +139,8 @@ def __minimize_route_time_diff(routes, starts, end, time_diff, n): times = [] for i, route in enumerate(routes): - times.append(get_trip_time(list_to_string(route), len(route), starts[i], end)) + times.append(__get_trip_time(__points_to_string(route), len(route), __points_to_string([starts[i]]), + __points_to_string([end]))) # Find the average trip time average_time = np.mean(times) @@ -181,7 +166,7 @@ def __minimize_route_time_diff(routes, starts, end, time_diff, n): return routes -def __remove_longest_waypoints(route_coordinates, start, end, max_time): +def __remove_longest_waypoints(route_coordinates: [db.Point], start: db.Point, end: db.Point, max_time): """ Takes a list of coordinates, a start point, an end point, and a maximum time and returns a list of coordinates :param route_coordinates: the list of coordinates @@ -191,7 +176,8 @@ def __remove_longest_waypoints(route_coordinates, start, end, max_time): :return: a list of coordinates """ # Find the trip time for the route - route_time = get_trip_time(list_to_string(route_coordinates), len(route_coordinates), start, end) + route_time = __get_trip_time(__points_to_string(route_coordinates), len(route_coordinates), + __points_to_string([start]), __points_to_string([end])) # If the trip time is greater than the max time, remove the waypoint with the longest distance from the mean if route_time > max_time: @@ -204,7 +190,7 @@ def __remove_longest_waypoints(route_coordinates, start, end, max_time): return route_coordinates -def __normalize_gps(coordinates, centroids): +def __normalize_points(coordinates: [db.Point], centroids: [db.Point]): """ Takes a list of coordinates and a list of centroids and returns a list of normalized coordinates and a list of normalized centroids @@ -214,8 +200,8 @@ def __normalize_gps(coordinates, centroids): """ # Create a list of latitudes and longitudes - latitudes = [i[0] for i in coordinates] - longitudes = [i[1] for i in coordinates] + latitudes = [i.latitude for i in coordinates] + longitudes = [i.longitude for i in coordinates] # Find the minimum and maximum latitudes and longitudes min_lat = min(latitudes) @@ -248,7 +234,7 @@ def __min_max_normalize(value, min_value, max_value): return (value - min_value) / (max_value - min_value) -def __find_closest_coordinate(coordinates, centroid): +def __find_closest_coordinate(coordinates: [db.Point], centroid: db.Point): """ Takes a list of coordinates and a centroid and returns the coordinate in the list that is closest to the centroid :param coordinates: the list of coordinates @@ -266,7 +252,7 @@ def __find_closest_coordinate(coordinates, centroid): return closest_coordinate -def __find_farthest_coordinate(coordinates, centroid): +def __find_farthest_coordinate(coordinates: [db.Point], centroid: db.Point): """ Takes a list of coordinates and a centroid and returns the coordinate in the list that is farthest from the centroid :param coordinates: the list of coordinates @@ -284,20 +270,21 @@ def __find_farthest_coordinate(coordinates, centroid): return farthest_coordinate -def __mean_center(coordinates): +def __mean_center(coordinates: [db.Point]): """ Takes a list of coordinates and returns the mean center of the coordinates :param coordinates: the list of coordinates :return: the mean center of the coordinates """ - return [sum([i[0] for i in coordinates]) / len(coordinates), sum([i[1] for i in coordinates]) / len(coordinates)] + return db.Point(np.mean([i.latitude for i in coordinates]), np.mean([i.longitude for i in coordinates])) -def __distance(coordinate1, coordinate2): +def __distance(coordinate1: db.Point, coordinate2: db.Point): """ Takes two coordinates and returns the distance between them :param coordinate1: the first coordinate :param coordinate2: the second coordinate :return: the distance between the two coordinates """ - return ((coordinate1[0] - coordinate2[0]) ** 2 + (coordinate1[1] - coordinate2[1]) ** 2) ** 0.5 \ No newline at end of file + return ((coordinate1.latitude - coordinate2.latitude) ** 2 + ( + coordinate1.longitude - coordinate2.longitude) ** 2) ** 0.5 -- cgit v1.2.3