def get_next_direction(self, start, goal): self.start = start self.goal = goal graph = self.create_graph(self.game_map) path = astar.astar_path(graph, start, goal) direction = self.convert_node_to_direction(path) return direction
def __init__(self, way_map, start, end): """ Args: way_map(WayMap): the map the trip takes place on start(2-tuple): starting point end(2-tuple): destination """ self.way_map = way_map self.start = start self.end = end try: self.list_of_nodes = astar_path(self.way_map.graph, self.start, self.end) except NetworkXNoPath: self.list_of_nodes = [] self.linestring = LineString(self.list_of_nodes) self.straightline_length = Path.straightline_distance(self.start, self.end) self.straightline = LineString([self.start, self.end]) self.deviation_factor = (self.linestring.length / self.straightline_length) self.obstacles = [] for polygon in list(polygonize([self.linestring, self.straightline])): self.obstacles.append(Obstacle(self.way_map, self.start, self.end, polygon))
def graph_routes(graph, find_longest): """ Return a list of routes through a network as (x, y) pair lists, with no edge repeated. Each node in the graph must have a "point" attribute with a Point object. """ # it's destructive _graph = graph.copy() # passed directly to shortest_path() weight = find_longest and 'length' or None # heuristic function for A* path-finding functions, see also: # http://networkx.lanl.gov/reference/algorithms.shortest_paths.html#module-networkx.algorithms.shortest_paths.astar heuristic = lambda n1, n2: _graph.node[n1]['point'].distance(_graph.node[n2]['point']) routes = [] while True: if not _graph.edges(): break leaves = [index for index in _graph.nodes() if _graph.degree(index) == 1] if len(leaves) == 1 or not find_longest: # add Y-junctions because with a single leaf, we'll get nowhere leaves += [index for index in _graph.nodes() if _graph.degree(index) == 3] if len(leaves) == 0: # just pick an arbitrary node and its neighbor out of the infinite loop node = [index for index in _graph.nodes() if _graph.degree(index) == 2][0] neighbor = _graph.neighbors(node)[0] leaves = [node, neighbor] distances = [(_graph.node[v]['point'].distance(_graph.node[w]['point']), v, w) for (v, w) in combinations(leaves, 2)] for (distance, v, w) in sorted(distances, reverse=find_longest): try: indexes = astar_path(_graph, v, w, heuristic, weight) except NetworkXNoPath: # try another continue for (v, w) in zip(indexes[:-1], indexes[1:]): _graph.remove_edge(v, w) points = [_graph.node[index]['point'] for index in indexes] coords = [(point.x, point.y) for point in points] routes.append(coords) # move on to the next possible route break return routes
def _graph_routes_main(graph, find_longest, time_coefficient=0.02): """ Return a list of routes through a network as (x, y) pair lists, with no edge repeated. Called from graph_routes(). Each node in the graph must have a "point" attribute with a Point object. The time_coefficient argument helps determine a time limit after which this function is killed off by means of a SIGALRM. With the addition of divide_points() in polygon_skeleton_graphs() as of version 0.6.0, this condition is much less likely to actually happen. The default value of 0.02 comes from a graph of times for a single state's generalized routes at a few zoom levels. I found that this function typically runs in O(n) time best case with some spikes up to O(n^2) and a general cluster around O(n^1.32). Introducing a time limit based on O(n^2) seemed too generous for large graphs, while the coefficient 0.02 seemed to comfortably cover graphs with up to tens of thousands of nodes. In the graph (new-hampshire-times.png) the functions are: - X-axis: graph size in nodes - Y-axis: compute time in seconds - Orange dashed good-enough limit: y = 0.02x - Blue bottom limit: y = 0.00005x - Green trend line: y = 2.772e-5x^1.3176 - Black upper bounds: y = 0.000001x^2 """ # it's destructive _graph = graph.copy() start_nodes, start_time = _graph.number_of_nodes(), time() # passed directly to shortest_path() weight = find_longest and 'length' or None # heuristic function for A* path-finding functions, see also: # http://networkx.lanl.gov/reference/algorithms.shortest_paths.html#module-networkx.algorithms.shortest_paths.astar heuristic = lambda n1, n2: point_distance(_graph.node[n1]['point'], _graph. node[n2]['point']) routes = [] while True: if not _graph.edges(): break leaves = [ index for index in _graph.nodes() if _graph.degree(index) == 1 ] if len(leaves) == 1 or not find_longest: # add Y-junctions because with a single leaf, we'll get nowhere leaves += [ index for index in _graph.nodes() if _graph.degree(index) == 3 ] if len(leaves) == 0: # just pick an arbitrary node and its neighbor out of the infinite loop node = [ index for index in _graph.nodes() if _graph.degree(index) == 2 ][0] neighbor = _graph.neighbors(node)[0] leaves = [node, neighbor] distances = [(point_distance(_graph.node[v]['point'], _graph.node[w]['point']), v, w) for (v, w) in combinations(leaves, 2)] for (distance, v, w) in sorted(distances, reverse=find_longest): try: indexes = astar_path(_graph, v, w, heuristic, weight) except NetworkXNoPath: # try another continue for (v, w) in zip(indexes[:-1], indexes[1:]): _graph.remove_edge(v, w) points = [_graph.node[index]['point'] for index in indexes] coords = [(point.x, point.y) for point in points] routes.append(coords) # move on to the next possible route break print(start_nodes, (time() - start_time), file=open('graph-routes-log.txt', 'a')) return routes
def _graph_routes_main(graph, find_longest, time_coefficient=0.02): """ Return a list of routes through a network as (x, y) pair lists, with no edge repeated. Called from graph_routes(). Each node in the graph must have a "point" attribute with a Point object. The time_coefficient argument helps determine a time limit after which this function is killed off by means of a SIGALRM. With the addition of divide_points() in polygon_skeleton_graphs() as of version 0.6.0, this condition is much less likely to actually happen. The default value of 0.02 comes from a graph of times for a single state's generalized routes at a few zoom levels. I found that this function typically runs in O(n) time best case with some spikes up to O(n^2) and a general cluster around O(n^1.32). Introducing a time limit based on O(n^2) seemed too generous for large graphs, while the coefficient 0.02 seemed to comfortably cover graphs with up to tens of thousands of nodes. In the graph (new-hampshire-times.png) the functions are: - X-axis: graph size in nodes - Y-axis: compute time in seconds - Orange dashed good-enough limit: y = 0.02x - Blue bottom limit: y = 0.00005x - Green trend line: y = 2.772e-5x^1.3176 - Black upper bounds: y = 0.000001x^2 """ # it's destructive _graph = graph.copy() start_nodes, start_time = _graph.number_of_nodes(), time() # passed directly to shortest_path() weight = find_longest and 'length' or None # heuristic function for A* path-finding functions, see also: # http://networkx.lanl.gov/reference/algorithms.shortest_paths.html#module-networkx.algorithms.shortest_paths.astar heuristic = lambda n1, n2: point_distance(_graph.node[n1]['point'], _graph.node[n2]['point']) routes = [] while True: if not _graph.edges(): break leaves = [index for index in _graph.nodes() if _graph.degree(index) == 1] if len(leaves) == 1 or not find_longest: # add Y-junctions because with a single leaf, we'll get nowhere leaves += [index for index in _graph.nodes() if _graph.degree(index) == 3] if len(leaves) == 0: # just pick an arbitrary node and its neighbor out of the infinite loop node = [index for index in _graph.nodes() if _graph.degree(index) == 2][0] neighbor = _graph.neighbors(node)[0] leaves = [node, neighbor] distances = [(point_distance(_graph.node[v]['point'], _graph.node[w]['point']), v, w) for (v, w) in combinations(leaves, 2)] for (distance, v, w) in sorted(distances, reverse=find_longest): try: indexes = astar_path(_graph, v, w, heuristic, weight) except NetworkXNoPath: # try another continue for (v, w) in zip(indexes[:-1], indexes[1:]): _graph.remove_edge(v, w) points = [_graph.node[index]['point'] for index in indexes] coords = [(point.x, point.y) for point in points] routes.append(coords) # move on to the next possible route break print >> open('graph-routes-log.txt', 'a'), start_nodes, (time() - start_time) return routes