def get_simulated_crosswalk(street_data, streets, width=1.8): """ Construct a simulated crosswalk :param street_data: street dictionary :param streets: list of dictionaries :param width: float, crosswalk width in meters :return: crosswalk dictionary """ right_border = shorten_border_for_crosswalk(street_data['right_border'], street_data['name'], streets, crosswalk_width=2, destination='to_intersection', exclude_parallel=False) left_border = shorten_border_for_crosswalk(street_data['left_border'], street_data['name'], streets, crosswalk_width=2, destination='to_intersection', exclude_parallel=False) right_border2 = shorten_border_for_crosswalk(street_data['right_border'], street_data['name'], streets, crosswalk_width=2 + width, destination='to_intersection', exclude_parallel=False) left_border2 = shorten_border_for_crosswalk(street_data['left_border'], street_data['name'], streets, crosswalk_width=2 + width, destination='to_intersection', exclude_parallel=False) crosswalk = { 'lane_id': '1C', 'name': street_data['name'], 'simulated': 'yes', 'right_border': [right_border[-1], left_border[-1]], 'left_border': [right_border2[-1], left_border2[-1]], 'median': shift_vector([right_border[-1], left_border[-1]], -width / 2.0), 'path_id': 0, 'path': [], 'lane_type': 'crosswalk', 'direction': 'undefined', 'nodes': [], 'nodes_coordinates': [], 'width': width, 'type': 'footway' } bearing = get_compass(crosswalk['right_border'][0], crosswalk['right_border'][-1]) crosswalk['bearing'] = bearing crosswalk['compass'] = get_compass_rhumb(bearing), crosswalk['length'] = get_border_length(crosswalk['median']) logger.debug('Created crosswalk for street %s %s' % (street_data['name'], street_data['compass'])) return crosswalk
def get_crosswalk_to_crosswalk_distance(crosswalk1, crosswalk2, median): """ Get the distance between two crosswalk along a median line of a guideway. It assumed that the crosswalks intersects the median. Returns -1 otherwise. :param crosswalk1: crosswalk dictionary :param crosswalk2: crosswalk dictionary :param median: list of coordinates :return: """ dist = [-1] border_types = ['left_border', 'right_border'] try: start_points = [get_line_intersection(crosswalk1[b], median) for b in border_types] end_points = [get_line_intersection(crosswalk2[b], median) for b in border_types] for start in start_points: if start is None: continue for end in end_points: if end is None: continue m1 = cut_border_by_point(median, start, ind=-1) m2 = cut_border_by_point(m1, end, ind=0) dist.append(get_border_length(m2)) except Exception as e: logger.error('Failed to calculate distance between crosswalks') logger.error('First crosswalk: %s, %s' % (crosswalk1['name'], crosswalk1['compass'])) logger.error('First crosswalk: %s, %s' % (crosswalk2['name'], crosswalk2['compass'])) logger.exception('%r' % e) return max(dist)
def get_lanes_close_to_the_intersection(x_data, crosswalk_width=1.82): """ Get a subset of lanes that are adjacent to the intersection center for construction of crosswalks. Lanes that ends at a distance to the center are excluded. :param lanes: :param crosswalk_width: :return: list of lane dictionaries """ close_lanes = [] for lane_data in x_data['merged_lanes']: if [n for n in lane_data['nodes'] if n in x_data['x_nodes']]: close_lanes.append(lane_data) continue dist = get_distance_from_point_to_line( (x_data['center_x'], x_data['center_y']), lane_data['median']) logger.debug("Distance from center to %d %s is %r" % (lane_data['id'], lane_data['name'], dist)) if get_distance_from_point_to_line( (x_data['center_x'], x_data['center_y']), lane_data['median']) < 4 * crosswalk_width: close_lanes.append(lane_data) continue median = shorten_border_for_crosswalk( lane_data['median'], lane_data['name'], x_data['merged_lanes'], crosswalk_width=5 * crosswalk_width, destination=lane_data['direction']) if get_border_length(median) < lane_data['length']: close_lanes.append(lane_data) return close_lanes
def set_guideway_length(g): """ Set guideway length as the length of its median :param g: guideway dictionary :return: None """ if g is None: logger.error('Guideway is None') else: g['length'] = get_border_length(g['median']) logger.debug('Guideway id %d length %r' % (g['id'], g['length']))
def remove_elements_beyond_radius(elements, nodes_dict, x0, y0, radius): """ Remove elements of a list having coordinates beyond certain radius :param elements: list of elements :param nodes_dict: dictionary :param x0: center coordinate :param y0: center coordinate :param radius: radius in meters :return: list of remaining elements """ for e in elements: if e['type'] != 'node': e['cropped'] = 'no' if 'left_border' in e: e['length'] = get_border_length(e['left_border']) else: e['length'] = 0 cropped_node_list = [] for n in e['nodes']: dist = great_circle_vec_check_for_nan(y0, x0, nodes_dict[n]['y'], nodes_dict[n]['x']) if dist <= radius: cropped_node_list.append(n) if 0 < len(cropped_node_list) < len(e['nodes']): e['cropped'] = 'yes' if 'left_border' in e: e['left_border'] = border_within_box( x0, y0, e['left_border'], radius) e['length'] = get_border_length(e['left_border']) if 'right_border' in e: e['right_border'] = border_within_box( x0, y0, e['right_border'], radius) if 'median' in e: e['median'] = border_within_box(x0, y0, e['median'], radius) if len(e['left_border']) < 1 or len(e['right_border']) < 1: e['nodes'] = [] logger.debug( 'Unable to obtain the portion of the path %d within radius. Skipping.' % e['id']) continue if 'name' in e['tags']: street_name = set([e['tags']['name']]) else: street_name = set(['no_name']) if 'tags' in e and 'split' in e['tags'] and e['tags'][ 'split'] == 'no': x = (e['left_border'][-1][0] + e['right_border'][-1][0]) / 2.0 y = (e['left_border'][-1][1] + e['right_border'][-1][1]) / 2.0 else: x = e['left_border'][-1][0] y = e['left_border'][-1][1] yy = nodes_dict[cropped_node_list[-1]]['y'] xx = nodes_dict[cropped_node_list[-1]]['x'] if great_circle_vec_check_for_nan(yy, xx, y, x) > 5.0: cropped_node_list.append( create_a_node_from_coordinates((x, y), nodes_dict, street_name)['osmid']) if 'tags' in e and 'split' in e['tags'] and e['tags'][ 'split'] == 'no': x = (e['left_border'][0][0] + e['right_border'][0][0]) / 2.0 y = (e['left_border'][0][1] + e['right_border'][0][1]) / 2.0 else: x = e['left_border'][0][0] y = e['left_border'][0][1] yy = nodes_dict[cropped_node_list[0]]['y'] xx = nodes_dict[cropped_node_list[0]]['x'] if great_circle_vec_check_for_nan(yy, xx, y, x) > 5.0: new_node = create_a_node_from_coordinates( (x, y), nodes_dict, street_name) cropped_node_list = [new_node['osmid']] + cropped_node_list e['nodes'] = cropped_node_list return [e for e in elements if e['type'] == 'node' or len(e['nodes']) > 0]
def get_simulated_crosswalk(street_data, streets, width=1.8): """ Construct a simulated crosswalk :param street_data: street dictionary :param streets: list of dictionaries :param width: float, crosswalk width in meters :return: crosswalk dictionary """ if is_highway(street_data): return None logger.debug("Simulated crosswalk for %s" % street_data['name']) right_border = shorten_border_for_crosswalk(street_data['right_border'], street_data['name'], streets, crosswalk_width=3, destination='to_intersection', exclude_parallel=True, max_reduction=130.0 ) left_border = shorten_border_for_crosswalk(street_data['left_border'], street_data['name'], streets, crosswalk_width=3, destination='to_intersection', exclude_parallel=True, max_reduction=130.0 ) right_border2 = shorten_border_for_crosswalk(street_data['right_border'], street_data['name'], streets, crosswalk_width=3 + width, destination='to_intersection', exclude_parallel=True, max_reduction=130.0 ) left_border2 = shorten_border_for_crosswalk(street_data['left_border'], street_data['name'], streets, crosswalk_width=3 + width, destination='to_intersection', exclude_parallel=False, max_reduction=130.0 ) vector = [right_border[-1], right_border2[-1]] resized_vector = extend_vector(vector, length=width, backward=False) vector2 = [get_closest_point(p, street_data['left_border']) for p in resized_vector] # logger.debug("Vector %r" % vector) # logger.debug("Resize %r" % resized_vector) # logger.debug("Vecto2 %r" % vector2) r_b = [right_border[-1], left_border[-1]] r_l = [shift_by_bearing_and_distance(r_b[0], width, [right_border[-1], right_border[-2]], bearing_delta=0.0), shift_by_bearing_and_distance(r_b[-1], width, [left_border[-1], left_border[-2]], bearing_delta=0.0)] crosswalk = { 'lane_id': '1C', 'name': street_data['name'], 'simulated': 'yes', # 'right_border': [vector[0], vector2[0]], # 'left_border': [resized_vector[1], vector2[1]], 'right_border': r_b, # [right_border[-1], left_border[-1]], 'left_border': r_l, # [right_border2[-1], left_border2[-1]], 'median': shift_vector([right_border[-1], left_border[-1]], -width / 2.0), 'path_id': 0, 'path': [], 'lane_type': 'crosswalk', 'direction': 'undefined', 'nodes': [], 'nodes_coordinates': [], 'width': width, 'type': 'footway' } bearing = get_compass(crosswalk['right_border'][0], crosswalk['right_border'][-1]) crosswalk['bearing'] = bearing crosswalk['compass'] = get_compass_rhumb(bearing), crosswalk['length'] = get_border_length(crosswalk['median']) if crosswalk['length'] > 50.0: return None if "id" in street_data: crosswalk["street_id"] = street_data["id"] logger.debug( 'Created crosswalk for street %s %s' % (street_data['name'], street_data['compass'])) return crosswalk
def add_lane(lane_data, merged_lane=None): """ Add lane to a merged lane :param lane_data: lane dictionary :param merged_lane: lane dictionary :return: merged lane dictionary """ if 'split' in lane_data: split = lane_data['path']['tags']['split'] else: split = 'no' if merged_lane is None: merged_lane = { 'width': [lane_data['width']], 'path_id': [lane_data['path_id']], 'path': [copy.deepcopy(lane_data['path'])], 'nodes': copy.deepcopy(lane_data['nodes']), 'left_border': copy.deepcopy(lane_data['left_border']), 'median': copy.deepcopy(lane_data['median']), 'right_border': copy.deepcopy(lane_data['right_border']), 'nodes_coordinates': copy.deepcopy(lane_data['nodes_coordinates']), 'right_shaped_border': copy.deepcopy(lane_data['right_shaped_border']), 'left_shaped_border': copy.deepcopy(lane_data['left_shaped_border']), 'shape_points': copy.deepcopy(lane_data['shape_points']), 'shape_length': copy.deepcopy(lane_data['shape_length']), 'split': [split], } else: split_transition = merged_lane['split'][-1] + '2' + split # split_transition options: yes2no, no2yes, yes2yes, no2no for k in ['left_border', 'right_border', 'median']: if split_transition == 'yes2no': merged_lane[k] = merged_lane[k][:-1] + lane_data[k][1:] elif split_transition == 'no2yes': merged_lane[k] = merged_lane[k][:-1] + lane_data[k][1:] else: merged_lane[k] += lane_data[k][1:] for k in ['nodes', 'nodes_coordinates']: merged_lane[k] += lane_data[k][1:] merged_lane['split'] += [split] for k in ['width', 'path_id', 'path']: merged_lane[k] += [lane_data[k]] if merged_lane['right_shaped_border'] is not None: merged_lane['right_shaped_border'] += lane_data['right_border'] if merged_lane['left_shaped_border'] is not None: merged_lane['left_shaped_border'] += lane_data['left_border'] for k in lane_data: if k not in [ 'width', 'path_id', 'path', 'nodes', 'left_border', 'right_border', 'median', 'nodes_coordinates', 'right_shaped_border', 'left_shaped_border', 'shape_length', 'shape_points', 'split' ]: merged_lane[k] = lane_data[k] merged_lane['length'] = get_border_length(merged_lane['median']) return merged_lane
def create_lane(p, nodes_dict, left_border=None, right_border=None, right_shaped_border=None, lane_id='1', lane_type='', direction='undefined', width=3.048, shape_points=16, shape_length=10.0, num_of_left_lanes=0, num_of_right_lanes=0, num_of_trunk_lanes=1, crosswalk_width=1.82): """ Create a lane from a path :param p: :param nodes_dict: :param left_border: :param right_border: :param right_shaped_border: :param lane_id: :param lane_type: :param direction: :param width: :param shape_points: :param shape_length: :param num_of_left_lanes: :param num_of_right_lanes: :param num_of_trunk_lanes: :param crosswalk_width: :return: """ lane_data = { 'lane_id': str(lane_id), 'path_id': p['id'], 'path': p, 'left_border': copy.deepcopy(left_border), 'lane_type': lane_type, 'direction': direction, 'width': width, 'shape_points': shape_points, 'shape_length': shape_length, 'num_of_left_lanes': num_of_left_lanes, 'num_of_right_lanes': num_of_right_lanes, 'num_of_trunk_lanes': num_of_trunk_lanes, 'crosswalk_width': crosswalk_width } if lane_type == 'cycleway': bicycle_lane_location = get_bicycle_lane_location(p) lane_data['bicycle_forward_location'] = bicycle_lane_location[ 'bicycle_forward_location'] lane_data['bicycle_backward_location'] = bicycle_lane_location[ 'bicycle_backward_location'] for x in p['tags']: lane_data[x] = p['tags'][x] if lane_type == 'left': lane_data['lane_id'] = str(lane_id) + 'L' elif lane_type == 'right': lane_data['lane_id'] = str(lane_id) + 'R' if 'name' in p['tags']: name = p['tags']['name'] elif 'highway' in p['tags'] and 'link' in p['tags']['highway']: name = p['tags']['highway'] else: name = 'no_name' lane_data['name'] = name lane_data['nodes'] = p['nodes'] lane_data['nodes_coordinates'] = [(nodes_dict[n]['x'], nodes_dict[n]['y']) for n in lane_data['nodes']] lane_data['right_shaped_border'] = None lane_data['left_shaped_border'] = None if right_border is None: lane_data['left_border'] = copy.deepcopy(left_border) lane_data['right_border'] = shift_list_of_nodes( left_border, [width] * len(left_border)) elif left_border is None: lane_data['right_border'] = copy.deepcopy(right_border) lane_data['left_border'] = shift_list_of_nodes(right_border, [-width] * len(right_border)) if 'L' in lane_data['lane_id']: right_border_with_inserted_points = add_incremental_points( right_border, n=shape_points, l=shape_length) delta_len = len(right_border_with_inserted_points) - len( right_border) shaped_widths = get_shaped_lane_width(-width, n=shape_points) width_list = shaped_widths[:delta_len] + [-width ] * len(right_border) if lane_data['lane_id'] == '1L': lane_data['right_shaped_border'] = copy.deepcopy( lane_data['right_border']) lane_data['left_shaped_border'] = shift_list_of_nodes( right_border_with_inserted_points, width_list) elif right_shaped_border is not None: lane_data['right_shaped_border'] = copy.deepcopy( right_shaped_border) lane_data['left_shaped_border'] = shift_list_of_nodes( right_shaped_border, width_list, direction_reference=lane_data['right_border']) else: lane_data['right_border'] = copy.deepcopy(right_border) lane_data['left_border'] = copy.deepcopy(left_border) if 'L' not in lane_data['lane_id']: lane_data['right_shaped_border'] = None lane_data['left_shaped_border'] = None lane_data['median'] = shift_list_of_nodes(lane_data['left_border'], [width / 2.0] * len(lane_data['left_border'])) lane_data['length'] = get_border_length(lane_data['median']) insert_referenced_nodes(lane_data, nodes_dict) return lane_data
def get_lane_meta_data(lane_data, all_lanes, intersection_data, max_distance=20.0): """ Create meta data dictionary for a lane (i.e. approach or exit) :param lane_data: dictionary of all lanes related to the intersection :param all_lanes: list of all lanes related to the intersection :param max_distance: max distance in meters for a transit stop to belong to a lane :param intersection_data: intersection data dictionary :return: dictionary """ meta_data = {'city': intersection_data['city']} stops = intersection_data['public_transit_nodes'] lane_data['city'] = intersection_data['city'] if 'num_of_trunk_lanes' in lane_data: meta_data['total_number_of_vehicle_lanes'] = lane_data['num_of_left_lanes'] \ + lane_data['num_of_right_lanes'] \ + lane_data['num_of_trunk_lanes'] meta_data['number_of_left-turning_lanes'] = lane_data[ 'num_of_left_lanes'] meta_data['number_of_right-turning_lanes'] = lane_data[ 'num_of_right_lanes'] if lane_data['lane_type'] == 'crosswalk': meta_data['identification'] = get_crosswalk_name(lane_data) else: if 'name' in lane_data: if 'no_name' in lane_data['name']: from_name, to_name = get_link_from_and_to(lane_data, all_lanes) if from_name is None or to_name is None: meta_data['identification'] = lane_data[ 'name'] + ' ' + lane_data['direction'] else: meta_data[ 'identification'] = from_name + ' - ' + to_name + ' Link ' + lane_data[ 'direction'] else: meta_data['identification'] = lane_data[ 'name'] + ' ' + lane_data['direction'] else: meta_data['identification'] = 'undefined_name' + ' ' + lane_data[ 'direction'] if 'id' in lane_data: meta_data['id'] = lane_data['id'] else: meta_data['id'] = None if len(get_connected_links(lane_data, all_lanes)) > 0: meta_data['right_turn_dedicated_link'] = 'yes' else: meta_data['right_turn_dedicated_link'] = 'no' meta_data['bicycle_lane_on_the_right'] = None meta_data['bicycle_lane_on_the_left'] = None if 'path' not in lane_data: meta_data['bicycle_lane_on_the_right'] = 'no' meta_data['bicycle_lane_on_the_left'] = 'no' else: for p in lane_data['path']: if key_value_check([('bicycle', 'no')], p): meta_data['bicycle_lane_on_the_right'] = 'no' meta_data['bicycle_lane_on_the_left'] = 'no' break elif is_shared(p): meta_data['bicycle_lane_on_the_right'] = 'shared' meta_data['bicycle_lane_on_the_left'] = 'no' break right, left = where_is_bicycle_lane(p) if meta_data['bicycle_lane_on_the_right'] is None: meta_data['bicycle_lane_on_the_right'] = right if meta_data['bicycle_lane_on_the_left'] is None: meta_data['bicycle_lane_on_the_left'] = left if 'rail' in lane_data['lane_type']: meta_data['rail_track'] = 'yes' else: meta_data['rail_track'] = 'no' node_set = set(lane_data['nodes']) for l in all_lanes: if 'rail' not in l['lane_type']: continue if len(node_set & set(l['nodes'])) > 0: meta_data['rail_track'] = 'yes' break if 'lane_type' in lane_data: meta_data['lane_type'] = lane_data['lane_type'] stop_sign = None if 'nodes_dict' in lane_data: for n in lane_data['nodes_dict']: if 'highway' in lane_data['nodes_dict'][n] and lane_data[ 'nodes_dict'][n]['highway'] == 'stop': stop_sign = 'yes' break traffic_signals = None if 'traffic_signals' in lane_data: meta_data['traffic_signals'] = lane_data['traffic_signals'] else: if 'nodes_dict' in lane_data: for n in lane_data['nodes_dict']: if 'highway' in lane_data['nodes_dict'][n] \ and "traffic_signals" in lane_data['nodes_dict'][n]['highway']: traffic_signals = 'yes' break if traffic_signals is None and stop_sign == 'yes': traffic_signals = 'no' elif stop_sign is None and traffic_signals == 'yes': stop_sign = 'no' meta_data['traffic_signals'] = traffic_signals meta_data['stop_sign'] = stop_sign meta_data['number_of_crosswalks'] = None if 'footway' in lane_data and lane_data['footway'] == 'crossing': meta_data['number_of_crosswalks'] = 1 if 'crossing' in lane_data: meta_data['number_of_crosswalks'] = 1 if 'traffic_signal' in lane_data['crossing']: meta_data['pedestrian_traffic_signals'] = 'yes' else: meta_data['pedestrian_traffic_signals'] = 'no' else: meta_data['pedestrian_traffic_signals'] = None meta_data['compass'] = lane_data['compass'] meta_data['length'] = get_border_length(lane_data['median']) if get_public_transit_stop(lane_data, stops, max_distance=max_distance): meta_data['public_transit_stop'] = 'yes' else: meta_data['public_transit_stop'] = None if 'railway' in lane_data and lane_data['railway'] == 'level_crossing': meta_data['crossing_railway'] = 'yes' else: meta_data['crossing_railway'] = None if 'median' in lane_data: curvature = get_border_curvature(lane_data['median']) else: curvature = get_border_curvature(lane_data['left_border']) meta_data['curvature'] = curvature num_of_lanes_list = [get_num_of_lanes(p) for p in lane_data['path']] if num_of_lanes_list: meta_data['max_number_of_lanes'] = max(num_of_lanes_list) meta_data['min_number_of_lanes'] = min(num_of_lanes_list) else: meta_data['max_number_of_lanes'] = 0 meta_data['min_number_of_lanes'] = 0 street_type = "undefined" if 'highway' in lane_data: street_type = lane_data['highway'] meta_data['street_type'] = street_type maxspeed = '25 mph' if 'maxspeed' in lane_data: maxspeed = lane_data['maxspeed'] meta_data['maxspeed'] = maxspeed meta_data['timestamp'] = str(datetime.datetime.now()) return meta_data
def shorten_border_for_crosswalk(input_border, street_name, lanes, crosswalk_width=10, destination='from_intersection', exclude_links=True, exclude_parallel=True, max_reduction=12.0, origin=True): """ Remove the portion of the input border overlapping with any crosswalk crossing the input border. Scan all lanes with street names other than the street the input border belongs to, and identify crosswalks related to each lane. :param input_border: list of coordinates :param street_name: string :param lanes: list of dictionaries :param crosswalk_width: float :param destination: string :param exclude_links: True if exclude links, False otherwise :return: list of coordinates """ border = copy.deepcopy(input_border) original_length = get_border_length(border) if destination == 'from_intersection': multi_string_index = -1 else: multi_string_index = 0 for l in lanes: if l['name'] == 'no_name' or l['name'] == street_name: continue if exclude_links and 'link' in l['name']: continue if 'median' in l: border_type = 'median' else: border_type = 'left_border' a = tuple(l[border_type][-2]) b = tuple(l[border_type][-1]) c = tuple(input_border[0]) d = tuple(input_border[-1]) bearing_delta = abs( get_angle_between_bearings(get_compass(a, b), get_compass(c, d))) """ bearing_delta = abs(get_angle_between_bearings(get_compass(l[border_type][-2], l[border_type][-1]), get_compass(input_border[0], input_border[-1]) ) ) """ if bearing_delta > 90.0: bearing_delta = (180.0 - bearing_delta) % 180.0 if bearing_delta < 30.0: if exclude_parallel: logger.debug( "Processing %s, excluding %s for shortening: almost parallel %r" % (street_name, l['name'], bearing_delta)) continue lb, rb = add_space_for_crosswalk(l, crosswalk_width=crosswalk_width) coord = lb + rb[::-1] polygon = geom.Polygon(coord) temp = cut_border_by_polygon(border, polygon, multi_string_index) if temp is not None: border = temp border = drop_small_edges(border) delta_len = original_length - get_border_length(border) if delta_len > max_reduction: logger.debug("Reduction is too large %r" % delta_len) border = copy.deepcopy(input_border) temp = reduce_line_by_distance(border, max_reduction, at_the_end=origin) border = temp border = drop_small_edges(border) return border