コード例 #1
0
def extrapolate_number_of_lanes(path_data, paths):
    """
    Add missing lane data to a path based on the previous path of the same street.
    Assuming that the number of the trunk lanes are same in the path coming out of the intersection.
    :param path_data: dictionary
    :param paths: list of dictionaries
    :return: None
    """

    if 'tags' in path_data \
            and 'lanes' not in path_data['tags'] \
            and 'turn:lanes' not in path_data['tags']\
            and 'direction' in path_data['tags']\
            and path_data['tags']['direction'] == 'from_intersection'\
            and 'bearing' in path_data \
            and path_data['bearing'] is not None \
            and len(path_data['nodes']) > 0\
            and 'name' in path_data['tags']:

        prev_path = [
            p for p in paths
            if 'name' in p['tags'] and p['tags']['name'] == path_data['tags']
            ['name'] and ('turn:lanes' in p['tags'] or 'lanes' in p['tags'])
            and 'bearing' in p and p['bearing'] is not None and
            abs(get_angle_between_bearings(p['bearing'],
                                           path_data['bearing'])) < 60.0
            and len(p['nodes']) > 0 and p['nodes'][-1] == path_data['nodes'][0]
        ]

        if len(prev_path) == 1:
            num_of_left_lanes, num_of_right_lanes, num_of_trunk_lanes = count_lanes(
                prev_path[0])
            path_data['tags']['lanes'] = num_of_trunk_lanes
            path_data['tags']['corrected'] = 'yes'
            path_data['tags']['correction_source_id'] = prev_path[0]['id']
コード例 #2
0
def shorten_border_for_crosswalk(input_border,
                                 street_name,
                                 lanes,
                                 crosswalk_width=10,
                                 destination='from_intersection',
                                 exclude_links=True,
                                 exclude_parallel=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)
    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'

        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)

    return border
コード例 #3
0
def get_destination_lane(lane_data, all_lanes, min_len=21.0):
    """
    Get destination lane for through driving
    :param lane_data: dictionary
    :param all_lanes: list of dictionaries
    :return: dictionary
    """

    # Try common node first
    res = [l for l in all_lanes
           if lane_data['nodes'][-1] == l['nodes'][0]
           and lane_data['lane_id'] == l['lane_id']
           and l['direction'] == 'from_intersection'
           and - 30.0 < get_angle_between_bearings(lane_data['bearing'], l['bearing']) < 30.0
           and ("length" not in l or l["length"] > min_len)
           ]
    if len(res) > 0:
        return res[0]

    # Try same street name
    res = [l for l in all_lanes
           if lane_data['name'] == l['name']
           and lane_data['lane_id'] == l['lane_id']
           and l['direction'] == 'from_intersection'
           and - 60.0 < get_angle_between_bearings(lane_data['bearing'], l['bearing']) < 60.0
           and get_distance_between_points(lane_data['median'][-1], l['median'][0]) < 15.0
           and ("length" not in l or l["length"] > min_len)
           ]
    if len(res) > 0:
        return res[0]

    # Try all other possible options
    res = [l for l in all_lanes
           if -30.0 < get_angle_between_bearings(lane_data['bearing'], l['bearing']) < 30.0
           and int(lane_data['lane_id'][0]) - 1 == get_lane_index_from_right(l)
           and l['direction'] == 'from_intersection'
           and get_distance_between_points(lane_data['median'][-1], l['median'][0]) < 10.0
           and ("length" not in l or l["length"] > min_len)
           ]
    if len(res) > 0:
        return res[0]

    return None
コード例 #4
0
def get_most_left_lane(lanes, name, direction, bearing):
    """
    Get the most left lane for a street for the specified direction
    :param lanes: list of lane dictionaries
    :param name: string
    :param direction: string
    :param bearing: float
    :return: lane dictionary
    """
    for l in lanes:
        if l['name'] == name and l[
                'direction'] == direction and get_lane_index_from_left(l) == 0:
            if abs(get_angle_between_bearings(bearing, l['bearing'])) < 15:
                return l
    return None
コード例 #5
0
def get_destination_lanes_for_u_turn(origin_lane, all_lanes):
    """
    Identifying the destination lane for the u-turn.
    Assuming that the origin and destination lanes must have the index from left equal to zero.
    :param origin_lane: lane dictionary of a left turn
    :param all_lanes: list of dictionaries
    :return: list of valid lane destinations for the left turn
    """
    if origin_lane['name'] == 'no_name':
        return []

    return [l for l in all_lanes
            if l['name'] == origin_lane['name']
            and l['direction'] == 'from_intersection'
            and get_lane_index_from_left(l) == 0
            and abs(get_angle_between_bearings(origin_lane['bearing'], l['bearing'])) > 150.0
            and get_distance_between_points(l['left_border'][0], origin_lane['left_border'][-1]) < 25.0
            and get_distance_between_points(l['left_border'][0], l['left_border'][-1]) > 25.0
            ]
コード例 #6
0
def get_sorted_lane_subset(lanes, name, bearing, direction, func):
    """
    Get subset of lanes for the specified name, bearing ang direction.
    Sort the results fy the specified function.
    :param lanes: list of lanes
    :param name: string
    :param bearing: float in degrees
    :param direction: string
    :param func: function name to provide sorting value
    :return: list of lanes
    """

    subset = [
        l for l in lanes if l['name'] == name and l['direction'] == direction
        and abs(get_angle_between_bearings(bearing, l['bearing'])) < 30
    ]

    if subset:
        return sorted(subset, key=func)
    else:
        return []
コード例 #7
0
def construct_u_turn_arc(origin_border, destination_border, number_of_points=12):
    """
    Construct a turn arc with the destination border
    :param origin_border: list of coordinates
    :param destination_border: list of coordinates
    :param number_of_points: integer
    :return: list of coordinates
    """

    bearing1 = get_compass(origin_border[-2], origin_border[-1])
    bearing2 = get_compass(destination_border[0], destination_border[1])
    angle = abs(get_angle_between_bearings(bearing1, bearing2))

    radius, landing_border = get_u_turn_radius_and_landing_border(origin_border, destination_border)
    if radius > 50:
        logger.debug('U-turn bearings %r, %r, angle %r' % (bearing1, bearing2, angle))
        logger.warning('Radius is too large %r, landing border %r' % (radius, landing_border))
        ob = cut_line_by_relative_distance(destination_border, 0.95)
        radius, landing_border = get_u_turn_radius_and_landing_border(ob, destination_border)
        logger.debug('Retry bearings %r, %r, angle %r' % (bearing1, bearing2, angle))
        logger.debug('Adjusted radius %r, landing border %r' % (radius, landing_border))
    else:
        ob = origin_border
    shift = [2.0 * radius * (math.sin(to_rad(angle / 2.0 * i / float(number_of_points)))) ** 2
             for i in range(0, number_of_points + 1)
             ]

    vec = [ob[-1], extend_vector(ob[-2:], length=30.0, backward=False, relative=True)[-1]]
    vector = [extend_vector(vec,
                            length=radius * (math.sin(to_rad(angle * i / float(number_of_points)))),
                            backward=False
                            )[1]
              for i in range(0, number_of_points + 1)
              ]

    arc = [shift_by_bearing_and_distance(vector[i], shift[i], ob[-2:], bearing_delta=-90.0)
           for i in range(0, number_of_points + 1)
           ]

    return arc[:-1] + landing_border
コード例 #8
0
def is_opposite_lane_exist(lane_data, lanes):
    """
    Check if an opposite traffic exists for the same street
    :param lane_data: lane dictionary
    :param lanes: list of lane dictionaries
    :return: True or False
    """
    if lane_data['direction'] == 'to_intersection':
        opposite_direction = 'from_intersection'
    else:
        opposite_direction = 'to_intersection'

    opposite_bearing = (lane_data['bearing'] + 180.0) % 360.0
    opposite_lanes = [
        l for l in lanes if l['name'] == lane_data['name']
        and opposite_direction in l['direction'] and
        abs(get_angle_between_bearings(opposite_bearing, l['bearing'])) < 30
    ]
    if opposite_lanes:
        return True
    else:
        return False
コード例 #9
0
def merge_lanes(lanes, nodes_dict):
    """
    Merge lanes for same street, direction, lane id
    :param lanes: list of dictionaries
    :param nodes_dict: dictionary of nodes
    :return: list of dictionaries
    """
    if lanes:
        lane_type = lanes[0]['lane_type']
        if lane_type == 'cycleway':
            lane_type = 'bicycle'
        elif lane_type == 'footway':
            lane_type = 'footway'
        elif lane_type == 'railway':
            lane_type = 'railway'
        else:
            lane_type = 'vehicle'

        logger.info('Start merging %d lanes of type %s' %
                    (len(lanes), lane_type))
    else:
        return []

    merged_lanes = []
    set_ids(lanes)
    for lane in [l for l in lanes if l['name'] == 'no_name']:
        merged_lanes.append(add_lane(lane, merged_lane=None))

    names = sorted(set([l['name'] for l in lanes if l['name'] != 'no_name']))

    for name in names:
        ids = sorted(set([l['lane_id'] for l in lanes if l['name'] == name]))

        for lane_id in ids:
            directions = sorted(
                set([
                    l['direction'] for l in lanes
                    if l['lane_id'] == lane_id and l['name'] == name
                ]))

            for direction in directions:
                similar_lanes = [
                    l for l in lanes
                    if l['lane_id'] == lane_id and l['name'] == name
                    and l['direction'] == direction and len(l['nodes']) > 0
                ]

                for similar_lane in similar_lanes:
                    if not isinstance(similar_lane['path'], dict):
                        continue
                    bearing = similar_lane['path']['bearing']
                    next_lanes = [
                        l for l in similar_lanes
                        if isinstance(l['path'], dict)
                        and similar_lane['nodes'][-1] == l['nodes'][0] and abs(
                            get_angle_between_bearings(l['path']['bearing'],
                                                       bearing)) < 60.0
                    ]
                    if len(next_lanes) == 0:
                        similar_lane['next'] = None
                    else:
                        if next_lanes[0]['path_id'] != similar_lane['path_id']:
                            similar_lane['next'] = next_lanes[0]['path_id']
                        else:
                            similar_lane['next'] = None

                    prev_lanes = [
                        l for l in similar_lanes
                        if isinstance(l['path'], dict)
                        and similar_lane['nodes'][0] == l['nodes'][-1] and abs(
                            get_angle_between_bearings(l['path']['bearing'],
                                                       bearing)) < 60.0
                    ]
                    if len(prev_lanes) == 0:
                        similar_lane['prev'] = None
                    else:
                        if prev_lanes[0]['path_id'] != similar_lane['path_id']:
                            similar_lane['prev'] = prev_lanes[0]['path_id']
                        else:
                            similar_lane['prev'] = None

                for start_lane in [
                        l for l in similar_lanes
                        if "prev" in l and l['prev'] is None
                ]:

                    merged_lane = add_lane(start_lane, merged_lane=None)

                    nxt = start_lane['next']

                    while nxt is not None:
                        next_lane = [
                            l for l in similar_lanes if l['path_id'] == nxt
                        ][0]
                        merged_lane = add_lane(next_lane,
                                               merged_lane=merged_lane)
                        nxt = next_lane['next']

                    merged_lanes.append(merged_lane)

    set_lane_bearing(merged_lanes)
    add_node_tags_to_lanes(merged_lanes, nodes_dict)
    insert_referenced_nodes_to_lanes(merged_lanes, nodes_dict)
    logger.info('Total %d merged lanes' % len(merged_lanes))
    return merged_lanes
コード例 #10
0
def get_intersection_meta_data(intersection_data):

    number_of_approaches = len(
        set([
            l['meta_data']['identification'] + '_' + l['meta_data']['compass']
            for l in intersection_data['merged_lanes']
            if 'to_intersection' in l['meta_data']['identification']
        ]))
    number_of_exits = len(
        set([
            l['meta_data']['identification'] + '_' + l['meta_data']['compass']
            for l in intersection_data['merged_lanes']
            if 'from_intersection' in l['meta_data']['identification']
        ]))

    number_of_railway_approaches = len(
        set([
            l['meta_data']['identification'] + '_' + l['meta_data']['compass']
            for l in intersection_data['merged_tracks']
            if 'to_intersection' in l['meta_data']['identification']
        ]))
    number_of_railway_exits = len(
        set([
            l['meta_data']['identification'] + '_' + l['meta_data']['compass']
            for l in intersection_data['merged_tracks']
            if 'from_intersection' in l['meta_data']['identification']
        ]))

    if number_of_approaches > 0:
        max_number_of_lanes_in_approach = max([0] + [
            l['meta_data']['max_number_of_lanes']
            for l in intersection_data['merged_lanes']
            if 'to_intersection' in l['meta_data']['identification']
        ])
        min_number_of_lanes_in_approach = min([
            l['meta_data']['min_number_of_lanes']
            for l in intersection_data['merged_lanes']
            if 'to_intersection' in l['meta_data']['identification']
        ])
    else:
        max_number_of_lanes_in_approach = 0
        min_number_of_lanes_in_approach = 0

    if number_of_exits > 0:
        max_number_of_lanes_in_exit = max([0] + [
            l['meta_data']['max_number_of_lanes']
            for l in intersection_data['merged_lanes']
            if 'from_intersection' in l['meta_data']['identification']
        ])
        min_number_of_lanes_in_exit = min([
            l['meta_data']['min_number_of_lanes']
            for l in intersection_data['merged_lanes']
            if 'from_intersection' in l['meta_data']['identification']
        ])
    else:
        max_number_of_lanes_in_exit = 0
        min_number_of_lanes_in_exit = 0

    # Stop signs
    if any([
            l['meta_data']['stop_sign'] == 'yes'
            for l in intersection_data['merged_lanes']
            if 'stop_sign' in l['meta_data']
    ]):
        stop_sign = 'yes'
    elif all([
            l['meta_data']['stop_sign'] == 'no'
            for l in intersection_data['merged_lanes']
            if 'stop_sign' in l['meta_data']
    ]):
        stop_sign = 'no'
    else:
        stop_sign = None

    # Traffic signals
    if any([
            l['meta_data']['traffic_signals'] == 'yes'
            for l in intersection_data['merged_lanes']
            if 'traffic_signals' in l['meta_data']
    ]):
        signal_present = 'yes'
    elif all([
            l['meta_data']['traffic_signals'] == 'no'
            for l in intersection_data['merged_lanes']
            if 'traffic_signals' in l['meta_data']
    ]):
        signal_present = 'no'
    else:
        signal_present = None

    if signal_present is None and stop_sign == 'yes':
        signal_present = 'no'
    elif stop_sign is None and signal_present == 'yes':
        stop_sign = 'no'

    # Pedestrian_traffic_signals
    if any([
            l['meta_data']['pedestrian_traffic_signals'] == 'yes'
            for l in intersection_data['merged_lanes']
    ]):
        pedestrian_traffic_signals = 'yes'
    elif all([
            l['meta_data']['pedestrian_traffic_signals'] == 'no'
            for l in intersection_data['merged_lanes']
    ]):
        pedestrian_traffic_signals = 'no'
    else:
        pedestrian_traffic_signals = None

    if pedestrian_traffic_signals == 'yes':
        signal_present = 'yes'

    number_of_center_bicycle_approaches = len(
        set([
            l['meta_data']['identification'] + '_' + l['meta_data']['compass']
            for l in intersection_data['merged_lanes']
            if 'to_intersection' in l['meta_data']['identification']
            and l['meta_data']['bicycle_lane_on_the_left'] is not None
            and 'yes' in l['meta_data']['bicycle_lane_on_the_left']
        ]))
    number_of_right_side_bicycle_approaches = len(
        set([
            l['meta_data']['identification'] + '_' + l['meta_data']['compass']
            for l in intersection_data['merged_lanes']
            if 'to_intersection' in l['meta_data']['identification']
            and l['meta_data']['bicycle_lane_on_the_right'] is not None
            and l['meta_data']['bicycle_lane_on_the_right'] != 'no'
        ]))
    number_of_center_bicycle_exits = len(
        set([
            l['meta_data']['identification'] + '_' + l['meta_data']['compass']
            for l in intersection_data['merged_lanes']
            if 'from_intersection' in l['meta_data']['identification']
            and l['meta_data']['bicycle_lane_on_the_left'] is not None
            and 'yes' in l['meta_data']['bicycle_lane_on_the_left']
        ]))
    number_of_right_side_bicycle_exits = len(
        set([
            l['meta_data']['identification'] + '_' + l['meta_data']['compass']
            for l in intersection_data['merged_lanes']
            if 'from_intersection' in l['meta_data']['identification']
            and l['meta_data']['bicycle_lane_on_the_right'] is not None
            and l['meta_data']['bicycle_lane_on_the_right'] != 'no'
        ]))

    max_angle = 0.0
    for l1 in intersection_data['merged_lanes']:
        if 'from_intersection' in l1['direction']:
            continue
        b1 = l1['bearing']
        max_angle = max(
            max_angle,
            max([0] + [
                abs(get_angle_between_bearings(l2['bearing'], b1))
                for l2 in intersection_data['merged_lanes']
                if 'from_intersection' in l2['direction']
                and l1['name'] != l2['name']
            ]))

    if [
            n for n in intersection_data['nodes']
            if 'subway' in intersection_data['nodes'][n]
            and intersection_data['nodes'][n]['subway'] == 'yes'
    ]:
        subway_station_present = 'yes'
    else:
        subway_station_present = 'no'

    rail_stations = [1 for n in intersection_data['nodes'] if 'light_rail' in intersection_data['nodes'][n]
                     and intersection_data['nodes'][n]['light_rail'] == 'yes'] + \
                    [1 for n in intersection_data['nodes'] if 'station' in intersection_data['nodes'][n]
                     and intersection_data['nodes'][n]['station'] == 'light_rail'] + \
                    [1 for n in intersection_data['nodes'] if 'railway' in intersection_data['nodes'][n]
                     and intersection_data['nodes'][n]['railway'] == 'station']

    bus_stops = [1 for n in intersection_data['nodes'] if 'highway' in intersection_data['nodes'][n]
                 and intersection_data['nodes'][n]['highway'] == 'bus_stop'] + \
                [1 for n in intersection_data['nodes'] if 'highway' in intersection_data['nodes'][n]
                 and 'trolley' in intersection_data['nodes'][n]['highway']]

    intersection_diameter = get_intersection_diameter(intersection_data)
    distance_to_next_intersection = get_distance_to_next_intersection(
        intersection_data, intersection_diameter)

    approach_street_types = get_list_of_highway_types(intersection_data,
                                                      "to_intersection")
    exit_street_types = get_list_of_highway_types(intersection_data,
                                                  "from_intersection")

    try:
        approach_list = [
            int(l['meta_data']['maxspeed'].split(' ')[0])
            for l in intersection_data['merged_lanes']
            if 'to_intersection' in l['meta_data']['identification']
        ]
        if approach_list:
            approach_max_speed = str(max(approach_list)) + ' ' + 'mph'
            approach_min_speed = str(min(approach_list)) + ' ' + 'mph'
        else:
            approach_max_speed = '25 mph'
            approach_min_speed = '25 mph'

        exit_list = [
            int(l['meta_data']['maxspeed'].split(' ')[0])
            for l in intersection_data['merged_lanes']
            if 'from_intersection' in l['meta_data']['identification']
        ]
        if exit_list:
            exit_max_speed = str(max(exit_list)) + ' ' + 'mph'
            exit_min_speed = str(min(exit_list)) + ' ' + 'mph'
        else:
            exit_max_speed = '25 mph'
            exit_min_speed = '25 mph'
    except:
        approach_max_speed = '25 mph'
        approach_min_speed = '25 mph'
        exit_max_speed = '25 mph'
        exit_min_speed = '25 mph'

    meta_data = {
        'number_of_approaches':
        number_of_approaches,
        'number_of_exits':
        number_of_exits,
        'max_number_of_lanes_in_approach':
        max_number_of_lanes_in_approach,
        'min_number_of_lanes_in_approach':
        min_number_of_lanes_in_approach,
        'number_of_railway_approaches':
        number_of_railway_approaches,
        'number_of_railway_exits':
        number_of_railway_exits,
        'max_number_of_lanes_in_exit':
        max_number_of_lanes_in_exit,
        'min_number_of_lanes_in_exit':
        min_number_of_lanes_in_exit,
        'number_of_center_bicycle_approaches':
        number_of_center_bicycle_approaches,
        'number_of_right_side_bicycle_approaches':
        number_of_right_side_bicycle_approaches,
        'number_of_center_bicycle_exits':
        number_of_center_bicycle_exits,
        'number_of_right_side_bicycle_exits':
        number_of_right_side_bicycle_exits,
        'signal_present':
        signal_present,
        'pedestrian_signal_present':
        pedestrian_traffic_signals,
        'diameter':
        intersection_diameter,
        'max_angle':
        max_angle,
        'max_curvature':
        max([0] + [
            l['meta_data']['curvature']
            for l in intersection_data['merged_lanes']
        ]),
        'min_curvature':
        min([
            l['meta_data']['curvature']
            for l in intersection_data['merged_lanes']
        ]),
        'distance_to_next_intersection':
        distance_to_next_intersection,
        'shortest_distance_to_railway_crossing':
        get_distance_to_railway_crossing(intersection_data),
        'subway_station_present':
        subway_station_present,
        'number_of_tram/train_stops':
        sum(rail_stations),
        'number_of_bus/trolley_stops':
        sum(bus_stops),
        'stop_sign':
        stop_sign,
        'approach_street_types':
        approach_street_types,
        'exit_street_types':
        exit_street_types,
        'approach_max_speed_limit':
        approach_max_speed,
        'approach_min_speed_limit':
        approach_min_speed,
        'exit_max_speed_limit':
        exit_max_speed,
        'exit_min_speed_limit':
        exit_min_speed,
        'approach_counts':
        count_oneways(intersection_data, 'to_intersection'),
        'exit_counts':
        count_oneways(intersection_data, 'from_intersection'),
    }

    meta_data['timestamp'] = str(datetime.datetime.now())
    return meta_data