def __init__(self, segment: Dict): self.strava_id = segment["strava_id"] self.name_str = segment["name"] self.start_latlng = segment["start_latlng"] self.end_latlng = segment["end_latlng"] self.bearing = calculate_initial_compass_bearing( point_a=tuple(self.start_latlng), point_b=tuple(self.end_latlng))
def _calculate_bearings(graph, nodes): """ Calculate the compass bearings for each sequential node paid in `nodes`. Lat/lon coordinates are expected to be node attributes in `graph` named 'y' and 'x'. Args: graph (networkx graph): containing lat/lon coordinates of each node in `nodes` nodes (list): list of nodes in sequential order that bearings will be calculated Returns: list[float] of the bearings between each node pair """ # bearings list bearings = [] edge_type = is_graph_line_or_circle(graph) node_pairs = list(zip(nodes[:-1], nodes[1:])) if edge_type == 'circle': node_pairs = [(nodes[-1], nodes[0])] + node_pairs + [(nodes[-1], nodes[0])] for pair in node_pairs: comp_bearing = calculate_initial_compass_bearing( (graph.nodes[pair[0]]['x'], graph.nodes[pair[0]]['y']), (graph.nodes[pair[1]]['x'], graph.nodes[pair[1]]['y']) ) bearings.append((pair[0], pair[1], comp_bearing)) return bearings
def add_direction(input_df): df = input_df[['Milliseconds', 'GPSLatitude', 'GPSLongitude']] df = df.drop_duplicates(subset='GPSLatitude') compassbearing_series = pd.Series() direction_x_series = pd.Series() direction_y_series = pd.Series() speed_series = pd.Series() df = df.reset_index() for row in range(0, len(df)): if row == len(df) - 1 or np.isnan( df.loc[row, 'GPSLatitude']) or np.isnan(df.loc[row + 1, 'GPSLatitude']): direction_x_series = direction_x_series.append(pd.Series( direction_x_series.iloc[-1]), ignore_index=True) direction_y_series = direction_y_series.append(pd.Series( direction_y_series.iloc[-1]), ignore_index=True) speed_series = speed_series.append(pd.Series( speed_series.iloc[-1]), ignore_index=True) compassbearing_series = compassbearing_series.append( pd.Series(compassbearing_series.iloc[-1]), ignore_index=True) else: lat1, long1 = df.loc[row, 'GPSLatitude'], df.loc[row, 'GPSLongitude'] lat2, long2 = df.loc[row + 1, 'GPSLatitude'], df.loc[row + 1, 'GPSLongitude'] distance = get_distance(lat1, long1, lat2, long2) * 1000 diff_timestamp = (df.loc[row + 1, 'Milliseconds'] - df.loc[row, 'Milliseconds']) / 1000 x, y, compassbearing = cb.calculate_initial_compass_bearing( lat1, long1, lat2, long2) direction_x_series = direction_x_series.append(pd.Series(x), ignore_index=True) direction_y_series = direction_y_series.append(pd.Series(y), ignore_index=True) speed_series = speed_series.append(pd.Series(distance / diff_timestamp), ignore_index=True) compassbearing_series = compassbearing_series.append( pd.Series(compassbearing), ignore_index=True) df = df.assign(Speed=speed_series.values) df = df.assign(DirectionX=direction_x_series.values) df = df.assign(DirectionY=direction_y_series.values) df = df.assign(CompassBearing=compassbearing_series.values) df = df.drop(columns=['index', 'Milliseconds']) input_df = pd.merge(input_df, df, how='left', on=['GPSLatitude', 'GPSLongitude']) return input_df
def azimuth(lat1, lon1, lat2, lon2): current_coord = (lat1, lon1) coord2 = (lat2, lon2) diff1 = -(current_coord[0] - coord2[0]) diff2 = -(current_coord[1] - coord2[1]) azimuth = cp.calculate_initial_compass_bearing(current_coord, coord2) return azimuth
def get_xy_to_crs_double_loops(gdf, n_det=1, double_loops=True): new_gdf = [] individ_gdf = [] for i in range(1, n_det + 1): a = pd.Series(gdf['detector ' + str(i)]) a_x = list(a.apply(lambda p: p.x)) a_y = list(a.apply(lambda p: p.y)) p_d = pd.Series(gdf['bearing ' + str(i)]) p_x = list(p_d.apply(lambda p: p.x)) p_y = list(p_d.apply(lambda p: p.y)) p = Proj(proj='utm', zone=34, ellps='WGS84', preserve_units=False) # Detector coordinates transformation lon, lat = p(a_x, a_y, inverse=True) c = {'lon': lon, 'lat': lat} df = pd.DataFrame(c) det_lonlat = df.apply(tuple, axis=1) det_lonlat = det_lonlat.rename('detector_' + str(i)) # Bearing points coordinates transformation p_lon, p_lat = p(p_x, p_y, inverse=True) p_c = {'lon_p': p_lon, 'lat_p': p_lat} df_p = pd.DataFrame(p_c) p1 = [tuple(xy) for xy in zip(df.lat, df.lon)] p2 = [tuple(xy) for xy in zip(df_p.lat_p, df_p.lon_p)] bearing = [compassbearing.calculate_initial_compass_bearing(p1[j], p2[j]) for j in range(0, len(p1))] gdf = gdf.drop(['detector ' + str(i)], axis=1) gdf = gdf.drop(['bearing ' + str(i)], axis=1) geom = [Point(xy) for xy in det_lonlat] gdf = pd.concat([gdf, det_lonlat], axis=1) gdf.insert(len(gdf.columns), 'detector_bearing_' + str(i), bearing) gdf_ind = gdf[['index', 'N1', 'N2', 'detector_' + str(i), 'detector_bearing_' + str(i)]] gdf_ind = gpd.GeoDataFrame(gdf_ind, crs='WGS84', geometry=geom) individ_gdf.append(gdf_ind) if double_loops: for i in range(1, n_det + 1): a = pd.Series(gdf['detector ' + str(i) + 'bis']) a_x = list(a.apply(lambda p: p.x)) a_y = list(a.apply(lambda p: p.y)) p_d = pd.Series(gdf['bearing ' + str(i + n_det)]) p_x = list(p_d.apply(lambda p: p.x)) p_y = list(p_d.apply(lambda p: p.y)) p = Proj(proj='utm', zone=34, ellps='WGS84', preserve_units=False) lon, lat = p(a_x, a_y, inverse=True) c = {'lon': lon, 'lat': lat} df = pd.DataFrame(c) det_lonlat = df.apply(tuple, axis=1) det_lonlat = det_lonlat.rename('detector_' + str(i) + 'bis') # Bearing points coordinates transformation p_lon, p_lat = p(p_x, p_y, inverse=True) p_c = {'lon_p': p_lon, 'lat_p': p_lat} df_p = pd.DataFrame(p_c) p1 = [tuple(xy) for xy in zip(df.lat, df.lon)] p2 = [tuple(xy) for xy in zip(df_p.lat_p, df_p.lon_p)] bearing = [compassbearing.calculate_initial_compass_bearing(p1[j], p2[j]) for j in range(0, len(p1))] gdf = gdf.drop(['detector ' + str(i) + 'bis'], axis=1) gdf = gdf.drop(['bearing ' + str(i + n_det)], axis=1) geom = [Point(xy) for xy in det_lonlat] gdf = pd.concat([gdf, det_lonlat], axis=1) gdf.insert(len(gdf.columns), 'detector_bearing_' + str(i) + 'bis', bearing) gdf_ind = gdf[['index', 'N1', 'N2', 'detector_' + str(i) + 'bis', 'detector_bearing_' + str(i) + 'bis']] gdf_ind = gpd.GeoDataFrame(gdf_ind, crs='WGS84', geometry=geom) individ_gdf.append(gdf_ind) gdf = gdf.drop(['geometry'], axis=1) geom = [Point(xy) for xy in gdf.detector_1] gdf = gpd.GeoDataFrame(gdf, crs='WGS84', geometry=geom) new_gdf.append(gdf) new_gdf.append(individ_gdf) return new_gdf
def test_directly_south_gives_180(): start_latlong = tuple(LatLon(lat=51.27987, lon=-2.77271)) end_latlong = tuple(LatLon(lat=51.27800, lon=-2.77271)) assert calculate_initial_compass_bearing( point_a=start_latlong, point_b=end_latlong) == pytest.approx(180.0, 0.01)
def test_directly_north_east_with_pos_lon_neg_lat(): start_latlong = tuple(LatLon(lat=-22.5001, lon=33.0001)) end_latlong = tuple(LatLon(lat=-22.5000, lon=33.00021)) assert calculate_initial_compass_bearing( point_a=start_latlong, point_b=end_latlong) == pytest.approx(45.0, 1)
def create_turn_weight_edge_attr(graph, length_weight='length', normalization_coefficient=1): """ add dictionary of turn weights to attributes for each edge Args: graph (NetworkX Graph): input graph with lat/lon attributes on nodes length_weight (str): edge attribute used for edge length normalization_coefficient (float): coefficient used to weight turn_weights relative to lengths Returns: NetworkX Graph with turn weight dictionary added to each edge. An edge's turn weight dictionary is keyed by possible predecessor edges. """ length_min, length_max, length_median, length_mean, length_stdev = generate_turn_weight_normalization_parameters( graph, length_weight=length_weight) graph_copy = graph.copy() #e_prim is edge that turn attributes are added to, and e_pred is predecessor edge for e_prim in graph.edges(keys=True): for e_pred in graph.edges(): if e_prim[0] == e_pred[1]: turn_start = e_pred[0] turn_middle = e_prim[0] turn_end = e_prim[1] key = e_prim[2] #create turn weights turn_start_lon = graph.nodes(data=True)[turn_start]['x'] turn_middle_lon = graph.nodes(data=True)[turn_middle]['x'] turn_end_lon = graph.nodes(data=True)[turn_end]['x'] turn_start_lat = graph.nodes(data=True)[turn_start]['y'] turn_middle_lat = graph.nodes(data=True)[turn_middle]['y'] turn_end_lat = graph.nodes(data=True)[turn_end]['y'] comp1_bearing = calculate_initial_compass_bearing( (turn_start_lat, turn_start_lon), (turn_middle_lat, turn_middle_lon)) comp2_bearing = calculate_initial_compass_bearing( (turn_middle_lat, turn_middle_lon), (turn_end_lat, turn_end_lon)) turn_angle = comp2_bearing - comp1_bearing if turn_angle < 0: turn_angle = 360 + turn_angle if (turn_angle >= 315 and turn_angle <= 360) or (turn_angle >= 0 and turn_angle < 45): turn_weight = 0 elif turn_angle >= 45 and turn_angle < 135: turn_weight = 1 elif turn_angle >= 225 and turn_angle < 315: turn_weight = 2 else: turn_weight = 4 #create turn_length turn_length = turn_weight * length_max * normalization_coefficient #add turn_length attribute if 'turn_length' not in graph_copy[e_prim[0]][e_prim[1]][key]: graph_copy[e_prim[0]][e_prim[1]][key]['turn_length'] = { e_pred[0]: turn_length } elif e_pred[0] not in graph_copy[e_prim[0]][ e_prim[1]][key]['turn_length']: graph_copy[e_prim[0]][e_prim[1]][key]['turn_length'][ e_pred[0]] = turn_length return (graph_copy)