diff --git a/src/c3nav/routing/graph.py b/src/c3nav/routing/graph.py index 4b97ed66..0e8f4be0 100644 --- a/src/c3nav/routing/graph.py +++ b/src/c3nav/routing/graph.py @@ -174,8 +174,7 @@ class Graph: # Router def build_routers(self): - level_routers = {} - room_routers = {} + routers = {} empty_distances = np.empty(shape=(len(self.level_transfer_points),) * 2, dtype=np.float16) empty_distances[:] = np.inf @@ -186,9 +185,8 @@ class Graph: sparse_levels[:] = -1 for i, level in enumerate(self.levels.values()): - router, add_room_routers = level.build_routers() - level_routers[level] = router - room_routers.update(add_room_routers) + routers.update(level.build_routers()) + router = routers[level] level_distances = empty_distances.copy() in_level_i = np.array(tuple(level.room_transfer_points.index(point) @@ -203,7 +201,9 @@ class Graph: g_sparse = csgraph_from_dense(sparse_distances, null_value=np.inf) shortest_paths, predecessors = shortest_path(g_sparse, return_predecessors=True) - return GraphRouter(shortest_paths, predecessors), level_routers, room_routers + + routers[self] = GraphRouter(shortest_paths, predecessors) + return routers def get_location_points(self, location: Location): if isinstance(location, PointLocation): @@ -229,7 +229,7 @@ class Graph: best_route = NoRoute # get routers - graph_router, level_routers, room_routers = self.build_routers() + routers = self.build_routers() # route within room orig_rooms = set(point.room for point in orig_points) @@ -243,8 +243,8 @@ class Graph: # if the points have common rooms, search for routes within those rooms if common_rooms: for room in common_rooms: - shortest_paths = room_routers[room].shortest_paths[orig_room_points[room][:, None], - dest_room_points[room]] + shortest_paths = routers[room].shortest_paths[orig_room_points[room][:, None], + dest_room_points[room]] distance = shortest_paths.min() # Is this route better than the previous ones? @@ -255,12 +255,12 @@ class Graph: from_point, to_point = np.argwhere(shortest_paths == distance)[0] from_point = orig_room_points[from_point] to_point = dest_room_points[to_point] - best_route = RoomRouteSegment(room, room_routers[room], from_point, to_point).as_route() + best_route = RoomRouteSegment(room, routers, from_point, to_point).as_route() # get reachable room transfer points and their distance # as a dictionary: global transfer point index => RoomRouteSegment - orig_room_transfers = self._room_transfers(orig_rooms, orig_room_points, room_routers, mode='orig') - dest_room_transfers = self._room_transfers(dest_rooms, dest_room_points, room_routers, mode='dest') + orig_room_transfers = self._room_transfers(orig_rooms, orig_room_points, routers, mode='orig') + dest_room_transfers = self._room_transfers(dest_rooms, dest_room_points, routers, mode='dest') # route within level orig_levels = set(room.level for room in orig_rooms) @@ -278,7 +278,7 @@ class Graph: for level in common_levels: o_points = orig_room_transfer_points[level] d_points = dest_room_transfer_points[level] - shortest_paths = level_routers[level].shortest_paths[o_points[:, None], d_points] + shortest_paths = routers[level].shortest_paths[o_points[:, None], d_points] # add distances to the the room transfer points to the rows and columns shortest_paths += np.array(tuple(orig_room_transfers[level.room_transfer_points[in_level_i]].distance @@ -296,13 +296,13 @@ class Graph: from_point = o_points[from_point] to_point = d_points[to_point] best_route = Route((orig_room_transfers[level.room_transfer_points[from_point]], - LevelRouteSegment(level, level_routers[level], from_point, to_point), + LevelRouteSegment(level, routers, from_point, to_point), dest_room_transfers[level.room_transfer_points[to_point]]), distance=distance) # get reachable level transfer points and their distance # as a dictionary: global transfer point index => Route - orig_level_transfers = self._level_transfers(orig_levels, orig_room_transfers, level_routers, mode='orig') - dest_level_transfers = self._level_transfers(orig_levels, dest_room_transfers, level_routers, mode='dest') + orig_level_transfers = self._level_transfers(orig_levels, orig_room_transfers, routers, mode='orig') + dest_level_transfers = self._level_transfers(orig_levels, dest_room_transfers, routers, mode='dest') # get reachable roomtransfer points for each level (points as room transfer point index within level) orig_level_transfer_points = self._allowed_points_index(self.level_transfer_points, orig_level_transfers) @@ -312,7 +312,7 @@ class Graph: if True: o_points = orig_level_transfer_points d_points = dest_level_transfer_points - shortest_paths = graph_router.shortest_paths[o_points[:, None], d_points] + shortest_paths = routers[self].shortest_paths[o_points[:, None], d_points] # add distances to the the room transfer points to the rows and columns shortest_paths += np.array(tuple(orig_level_transfers[self.level_transfer_points[in_graph_i]].distance @@ -328,12 +328,12 @@ class Graph: from_point = o_points[from_point] to_point = d_points[to_point] best_route = Route((orig_level_transfers[self.level_transfer_points[from_point]], - GraphRouteSegment(self, graph_router, from_point, to_point), + GraphRouteSegment(self, routers, from_point, to_point), dest_level_transfers[self.level_transfer_points[to_point]]), distance=distance) return best_route - def _room_transfers(self, rooms, room_points, room_routers, mode): + def _room_transfers(self, rooms, room_points, routers, mode): if mode not in ('orig', 'dest'): raise ValueError @@ -343,9 +343,9 @@ class Graph: points = room_points[room] if mode == 'orig': - shortest_paths = room_routers[room].shortest_paths[points[:, None], room_transfer_points] + shortest_paths = routers[room].shortest_paths[points[:, None], room_transfer_points] else: - shortest_paths = room_routers[room].shortest_paths[room_transfer_points[:, None], points] + shortest_paths = routers[room].shortest_paths[room_transfer_points[:, None], points] # noinspection PyTypeChecker for from_i, to_i in np.argwhere(shortest_paths != np.inf): @@ -355,11 +355,11 @@ class Graph: transfer_i = room.points[to_i if mode == 'orig' else from_i] if transfer_i not in room_transfers or room_transfers[transfer_i].distance < distance: - room_transfers[transfer_i] = RoomRouteSegment(room, room_routers[room], from_i, to_i) + room_transfers[transfer_i] = RoomRouteSegment(room, routers, from_i, to_i) return room_transfers - def _level_transfers(self, levels, all_room_transfers, level_routers, mode): + def _level_transfers(self, levels, all_room_transfers, routers, mode): if mode not in ('orig', 'dest'): raise ValueError @@ -375,10 +375,10 @@ class Graph: distances = np.array(distances) if mode == 'orig': - shortest_paths = level_routers[level].shortest_paths[points[:, None], level_transfer_points] + shortest_paths = routers[level].shortest_paths[points[:, None], level_transfer_points] shortest_paths += distances[:, None] else: - shortest_paths = level_routers[level].shortest_paths[level_transfer_points[:, None], points] + shortest_paths = routers[level].shortest_paths[level_transfer_points[:, None], points] shortest_paths += distances # noinspection PyTypeChecker @@ -390,7 +390,7 @@ class Graph: transfer_i = level.room_transfer_points[to_i if mode == 'orig' else from_i] room_transfer_i = level.room_transfer_points[from_i if mode == 'orig' else to_i] if transfer_i not in level_transfers or level_transfers[transfer_i].distance < distance: - segments = [LevelRouteSegment(level, level_routers[level], from_i, to_i)] + segments = [LevelRouteSegment(level, routers, from_i, to_i)] if mode == 'orig': segments.insert(0, all_room_transfers[room_transfer_i]) else: diff --git a/src/c3nav/routing/level.py b/src/c3nav/routing/level.py index 17e42808..31fb32a7 100644 --- a/src/c3nav/routing/level.py +++ b/src/c3nav/routing/level.py @@ -195,7 +195,7 @@ class GraphLevel(): # Routing def build_routers(self): - room_routers = {} + routers = {} empty_distances = np.empty(shape=(len(self.room_transfer_points),) * 2, dtype=np.float16) empty_distances[:] = np.inf @@ -207,7 +207,7 @@ class GraphLevel(): for i, room in enumerate(self.rooms): router = room.build_router() - room_routers[room] = router + routers[room] = router room_distances = empty_distances.copy() in_room_i = np.array(tuple(room.points.index(point) for point in room.room_transfer_points)) @@ -222,7 +222,9 @@ class GraphLevel(): g_sparse = csgraph_from_dense(sparse_distances, null_value=np.inf) shortest_paths, predecessors = shortest_path(g_sparse, return_predecessors=True) - return LevelRouter(shortest_paths, predecessors, room_transfers), room_routers + + routers[self] = LevelRouter(shortest_paths, predecessors, room_transfers) + return routers LevelRouter = namedtuple('LevelRouter', ('shortest_paths', 'predecessors', 'rooms_transfers', )) diff --git a/src/c3nav/routing/route.py b/src/c3nav/routing/route.py index 3409d687..61224448 100644 --- a/src/c3nav/routing/route.py +++ b/src/c3nav/routing/route.py @@ -18,13 +18,22 @@ class RouteSegment(ABC): def as_route(self): return Route([self]) + def _get_points(self): + points = [self.to_point] + first = self.from_point + current = self.to_point + while current != first: + current = self.router.predecessors[first, current] + points.append(current) + return tuple(reversed(points)) + @cached_property def distance(self): return self.router.shortest_paths[self.from_point, self.to_point] class RoomRouteSegment(RouteSegment): - def __init__(self, room, router, from_point, to_point): + def __init__(self, room, routers, from_point, to_point): """ Route segment within a Room :param room: GraphRoom @@ -32,7 +41,7 @@ class RoomRouteSegment(RouteSegment): :param from_point: in-room index of first point :param to_point: in-room index of last point """ - super().__init__(router, from_point, to_point) + super().__init__(routers[room], from_point, to_point) self.room = room self.global_from_point = room.points[from_point] self.global_to_point = room.points[to_point] @@ -43,12 +52,12 @@ class RoomRouteSegment(RouteSegment): class LevelRouteSegment(RouteSegment): - def __init__(self, level, router, from_point, to_point): + def __init__(self, level, routers, from_point, to_point): """ Route segment within a Level (from room transfer point to room transfer point) :param level: GraphLevel """ - super().__init__(router, from_point, to_point) + super().__init__(routers[level], from_point, to_point) self.level = level self.global_from_point = level.room_transfer_points[from_point] self.global_to_point = level.room_transfer_points[to_point] @@ -59,12 +68,12 @@ class LevelRouteSegment(RouteSegment): class GraphRouteSegment(RouteSegment): - def __init__(self, graph, router, from_point, to_point): + def __init__(self, graph, routers, from_point, to_point): """ Route segment within a Graph (from level transfer point to level transfer point) :param graph: Graph """ - super().__init__(router, from_point, to_point) + super().__init__(routers[graph], from_point, to_point) self.graph = graph self.global_from_point = graph.level_transfer_points[from_point] self.global_to_point = graph.level_transfer_points[to_point]