示例#1
0
def find_routes(departure_coordinate, arrival_coordinate, departure_time):
    """
    :param departure_coordinate:  tuple of (lat, long)
    :param arrival_coordinate: tuple of (lat, long)
    :param departure_time: Departure time string
    :return: Json with directions
    """

    # Load transit models
    caltrain = CaltrainModel()

    # Create basic nodes
    departure_node = Node(modes=["bike"],
                          id="departure",
                          name="Departure",
                          direction="",
                          lat=departure_coordinate[0],
                          lon=departure_coordinate[1])

    arrival_node = Node(modes=["bike"],
                        id="arrival",
                        name="Arrival",
                        direction="",
                        lat=arrival_coordinate[0],
                        lon=arrival_coordinate[1])

    setup_DB(caltrain.nodes + [departure_node] + [arrival_node])

    if VIZ:
        viz.init_plot()
        viz.set_all_nodes(Node.get_all_nodes())
        viz.set_HnD_node(Node.find_node_by_id("departure"),
                         Node.find_node_by_id("arrival"))

    #
    # Graph search
    #

    # Set initial node
    first_node = Node.find_node_by_id("departure")
    first_node.arrival_time = time_str_to_int(departure_time)
    first_node.cost = 0
    final_node_id = "arrival"

    # Remove connections that are in the past, or too far off in the future
    caltrain.keep_connections_bw(first_node.arrival_time - 1,
                                 first_node.arrival_time + 3 * 60)

    open_set = [first_node]

    closed_set = []
    solution_number = 0
    solutions = {}

    while len(open_set) > 0:
        if DEBUG:
            print "\nOpen set:"
            pprint.pprint(open_set)

        # Get next node to explore
        current_node = Node.cheapest_node(open_set,
                                          h_func=heuristic_time_to_destination(
                                              Node.find_node_by_id("arrival")))

        if VIZ:
            viz.set_current_node(current_node)

        if DEBUG:
            print "\nCurrent node:"
            print current_node

        open_set.remove(current_node)
        closed_set.append(current_node)

        if DEBUG:
            print "\nOpen set:"
            pprint.pprint(open_set)

        # Check for goal
        if current_node.id == final_node_id:
            solution_number += 1
            solution_str = "Solution #: {}\n".format(solution_number)

            solution_node = current_node
            wait_at_previous_node = 0
            while solution_node is not None:
                wait_at_current_node = wait_at_previous_node
                wait_at_previous_node = solution_node.time_waiting
                solution_str += "{} {} : {} {}\n".format(
                    solution_node.name,
                    time_int_to_str(solution_node.arrival_time),
                    time_int_to_str(solution_node.arrival_time +
                                    wait_at_current_node),
                    solution_node.from_mode)

                if solution_node.from_mode == "bike":
                    solution_str += "\t{} for {} mins\n".format(
                        solution_node.from_mode, solution_node.time_moving)

                solution_node = solution_node.from_node

            solutions[solution_number] = solution_str

            if DEBUG:
                print "\n\n--\n\n"
                print solution_str

            if solution_number < NUMBER_OF_SOLUTIONS:
                continue
            else:
                break

        # Add connections for caltrain
        if "caltrain" in current_node.modes:
            all_connections = caltrain.connections

            # Find connections from current node
            relevant_connections = []
            for connection in all_connections:
                if connection.start_node_id == current_node.id:
                    relevant_connections.append(connection)

            # Find connections that are still possible
            possible_connections = []
            for connection in relevant_connections:
                if connection.start_time >= current_node.arrival_time:
                    possible_connections.append(connection)

            # Set connections
            current_node.connections += possible_connections

        # Add connections for bikes
        if "bike" in current_node.modes:
            bike_connections = create_bike_connections(current_node,
                                                       compute_end_time=False)

            # Prune bike connections
            pruned_connections = []
            for connection in bike_connections:
                conn_destination_node = Node.find_node_by_id(
                    connection.end_node_id)
                conn_departure_node = Node.find_node_by_id(
                    connection.start_node_id)

                # 1. Ignore biking b/w NB and SB stations
                if conn_departure_node.name == conn_destination_node.name:
                    continue

                # 2. Don't bike between stations of the same provider
                if "caltrain" in conn_departure_node.modes and "caltrain" in conn_destination_node.modes:
                    continue

                # 3. Do not create loops
                keep_connection = True
                prev_node = current_node.from_node
                while prev_node is not None:
                    if prev_node.id == conn_destination_node.id:
                        keep_connection = False
                        break
                    prev_node = prev_node.from_node
                if not keep_connection:
                    continue

                # We want to keep this connection. Calculate end_time.
                connection.end_time = connection.start_time + biking_duration_bw_nodes(
                    conn_departure_node, conn_destination_node)
                pruned_connections.append(connection)

            current_node.connections += pruned_connections

        if DEBUG:
            print "\nNew connections:"

        # Iterate over connections and add nodes
        new_nodes = []
        for connection in current_node.connections:
            new_node_id = connection.end_node_id
            new_node = Node.find_node_by_id(new_node_id)
            new_node.arrival_time = connection.end_time
            new_node.from_node = current_node
            new_node.from_mode = connection.mode

            if current_node.id == "departure":  # Mark new node as first "real" node, aka first destination node to.
                new_node.first_dest_node = True

            # Cost
            time_waiting = connection.start_time - current_node.arrival_time
            time_moving = connection.end_time - connection.start_time
            bike_penalty = 1.0 if connection.mode == "bike" else 1.0
            waiting_penalty = 1.0 if current_node.first_dest_node else 1.0
            new_node.cost = current_node.cost + time_moving * bike_penalty + time_waiting * waiting_penalty

            if DEBUG:
                print connection
                print "time_waiting", time_waiting, "time_moving", time_moving, "cost", new_node.cost

            new_node.time_waiting = time_waiting
            new_node.time_moving = time_moving

            new_nodes.append(new_node)

        # Add new node to open set
        open_set += new_nodes

        # Prune open set for duplicates
        open_set.sort(key=lambda x: x.cost)
        unique_open_set = []
        i = 0
        prev_node = None
        for i in range(len(open_set)):
            curr_node = open_set[i]
            accept = False
            if prev_node is None:
                accept = True
            elif prev_node.name != curr_node.name or prev_node.arrival_time != curr_node.arrival_time:
                accept = True

            if accept:
                unique_open_set.append(curr_node)
                prev_node = curr_node
        open_set = unique_open_set

        if VIZ:
            viz.set_nbr_node(open_set)
            viz.show_plot()

        if DEBUG:
            print "\nOpen set:"
            pprint.pprint(open_set)
            print "\n-----"
            raw_input()

    if DEBUG:
        print "opened nodes:", len(open_set)

    if VIZ:
        viz.keep_open()

    return solutions