team-3/src/c3nav/routing/graph.py

543 lines
25 KiB
Python
Raw Normal View History

import os
import pickle
from collections import OrderedDict, namedtuple
from itertools import combinations
import numpy as np
from django.conf import settings
from scipy.sparse.csgraph._shortest_path import shortest_path
from scipy.sparse.csgraph._tools import csgraph_from_dense
from c3nav.mapdata.models import Elevator, Level
from c3nav.mapdata.models.geometry import LevelConnector
from c3nav.mapdata.models.locations import AreaLocation, Location, LocationGroup, PointLocation
from c3nav.routing.connection import GraphConnection
from c3nav.routing.exceptions import AlreadyThere, NoRouteFound, NotYetRoutable
from c3nav.routing.level import GraphLevel
from c3nav.routing.point import GraphPoint
from c3nav.routing.route import NoRoute, Route
from c3nav.routing.routesegments import (GraphRouteSegment, LevelRouteSegment, RoomRouteSegment, SegmentRoute,
SegmentRouteWrapper)
2016-12-03 19:09:39 +01:00
class Graph:
2016-12-16 11:38:25 +01:00
graph_cached = None
graph_cached_mtime = None
default_filename = os.path.join(settings.DATA_DIR, 'graph.pickle')
def __init__(self, mtime=None):
self.mtime = mtime
self.levels = OrderedDict()
for level in Level.objects.all():
self.levels[level.name] = GraphLevel(self, level)
2016-12-10 12:19:31 +01:00
self.points = []
self.level_transfer_points = None
self.elevatorlevel_points = None
2016-12-05 13:39:22 +01:00
2016-12-10 12:07:52 +01:00
# Building the Graph
2016-12-03 19:09:39 +01:00
def build(self):
self._built_level_transfer_points = []
self._built_levelconnector_points = {}
self._built_elevatorlevel_points = {}
2016-12-03 19:09:39 +01:00
for level in self.levels.values():
level.build()
2016-12-10 12:07:52 +01:00
# collect rooms and points
rooms = sum((level.rooms for level in self.levels.values()), [])
self.points = sum((level._built_points for level in self.levels.values()), [])
2016-12-10 12:07:52 +01:00
# create connections between levels
print()
self.connect_levelconnectors()
self.connect_elevators()
# finishing build: creating numpy arrays and convert everything else to tuples
2016-12-14 00:39:32 +01:00
self.points = tuple(set(self.points))
2016-12-10 12:07:52 +01:00
for i, room in enumerate(rooms):
2016-12-10 12:07:52 +01:00
room.i = i
for i, point in enumerate(self.points):
point.i = i
self.level_transfer_points = tuple(point.i for point in self._built_level_transfer_points)
for level in self.levels.values():
level.finish_build()
print()
print('Total:')
self.print_stats()
print()
print('Points per room:')
for name, level in self.levels.items():
print(('Level %s:' % name), *(sorted((len(room.points) for room in level.rooms), reverse=True)))
def print_stats(self):
print('%d points' % len(self.points))
print('%d rooms' % sum(len(level.rooms) for level in self.levels.values()))
print('%d level transfer points' % len(self.level_transfer_points))
print('%d connections' % sum(level.connection_count() for level in self.levels.values()))
2016-12-10 12:07:52 +01:00
def add_levelconnector_point(self, levelconnector, point):
self._built_levelconnector_points.setdefault(levelconnector.name, []).append(point)
def add_elevatorlevel_point(self, elevatorlevel, point):
self._built_elevatorlevel_points[elevatorlevel.name] = point
2016-12-10 12:07:52 +01:00
def connect_levelconnectors(self):
for levelconnector in LevelConnector.objects.all():
center = levelconnector.geometry.centroid
points = self._built_levelconnector_points.get(levelconnector.name, [])
2016-12-13 23:32:19 +01:00
rooms = set(point.room for point in points if point.room is not None)
connected_levels = set(room.level for room in rooms)
2016-12-10 12:07:52 +01:00
2016-12-13 23:32:19 +01:00
should_levels = tuple(level.name for level in levelconnector.levels.all())
missing_levels = set(should_levels) - set(level.level.name for level in connected_levels)
if missing_levels:
print('levelconnector %s on levels %s at (%.2f, %.2f) is not connected to levels %s!' %
(levelconnector.name, ', '.join(should_levels), center.x, center.y, ', '.join(missing_levels)))
2016-12-10 12:07:52 +01:00
continue
2016-12-13 23:32:19 +01:00
center_point = GraphPoint(center.x, center.y, None)
2016-12-10 12:07:52 +01:00
self.points.append(center_point)
self._built_level_transfer_points.append(center_point)
2016-12-10 12:07:52 +01:00
2016-12-13 23:32:19 +01:00
for level in connected_levels:
level._built_room_transfer_points.append(center_point)
level._built_points.append(center_point)
2016-12-10 12:07:52 +01:00
for room in rooms:
room._built_points.append(center_point)
2016-12-10 12:07:52 +01:00
for point in points:
center_point.connect_to(point)
point.connect_to(center_point)
2016-12-10 12:07:52 +01:00
def connect_elevators(self):
for elevator in Elevator.objects.all():
elevatorlevels = tuple(elevator.elevatorlevels.all())
for level1, level2 in combinations(elevatorlevels, 2):
point1 = self._built_elevatorlevel_points[level1.name]
point2 = self._built_elevatorlevel_points[level2.name]
2016-12-19 15:11:11 +01:00
center = GraphPoint((point1.x+point2.x)/2, (point1.y+point2.y)/2, None)
self.points.append(center)
self._built_level_transfer_points.append(center)
for room in (point1.room, point2.room):
2016-12-19 15:11:11 +01:00
room._built_points.append(center)
room.level._built_room_transfer_points.append(center)
room.level._built_points.append(center)
2016-12-18 00:40:10 +01:00
direction_up = level2.altitude > level1.altitude
2016-12-19 15:11:11 +01:00
dist = abs(level2.altitude-level1.altitude)
2016-12-19 15:11:11 +01:00
point1.connect_to(center, ctype=('elevator_up' if direction_up else 'elevator_down'), distance=dist)
center.connect_to(point2, ctype=('elevator_up' if direction_up else 'elevator_down'), distance=dist)
point2.connect_to(center, ctype=('elevator_down' if direction_up else 'elevator_up'), distance=dist)
center.connect_to(point1, ctype=('elevator_down' if direction_up else 'elevator_up'), distance=dist)
2016-12-10 12:07:52 +01:00
# Loading/Saving the Graph
def serialize(self):
return (
{name: level.serialize() for name, level in self.levels.items()},
[point.serialize() for point in self.points],
self.level_transfer_points,
)
def save(self, filename=None):
if filename is None:
filename = self.default_filename
with open(filename, 'wb') as f:
pickle.dump(self.serialize(), f)
@classmethod
def unserialize(cls, data, mtime):
levels, points, level_transfer_points = data
graph = cls(mtime=mtime)
2016-12-13 23:32:19 +01:00
for name, level in levels.items():
graph.levels[name].unserialize(level)
rooms = sum((level.rooms for level in graph.levels.values()), ())
graph.points = tuple(GraphPoint(x, y, None if room is None else rooms[room]) for x, y, room in points)
graph.level_transfer_points = level_transfer_points
for i, room in enumerate(rooms):
room.i = i
for i, point in enumerate(graph.points):
point.i = i
return graph
@classmethod
def load(cls, filename=None):
2016-12-16 11:38:25 +01:00
do_cache = False
if filename is None:
2016-12-16 11:38:25 +01:00
do_cache = True
filename = cls.default_filename
2016-12-16 11:38:25 +01:00
graph_mtime = None
if do_cache:
graph_mtime = os.path.getmtime(filename)
if cls.graph_cached is not None:
if cls.graph_cached_mtime == graph_mtime:
2016-12-16 11:38:25 +01:00
return cls.graph_cached
with open(filename, 'rb') as f:
graph = cls.unserialize(pickle.load(f), graph_mtime)
2016-12-16 11:38:25 +01:00
if do_cache:
cls.graph_cached_mtime = graph_mtime
2016-12-16 11:38:25 +01:00
cls.graph_cached = graph
graph.print_stats()
return graph
2016-12-10 12:07:52 +01:00
# Drawing
def draw_pngs(self, points=True, lines=True):
for level in self.levels.values():
level.draw_png(points, lines)
2016-12-03 19:09:39 +01:00
2016-12-10 12:07:52 +01:00
# Router
2016-12-21 13:31:56 +01:00
def build_routers(self, allowed_ctypes, allow_nonpublic, avoid, include):
2016-12-17 14:09:38 +01:00
routers = {}
empty_distances = np.empty(shape=(len(self.level_transfer_points),) * 2, dtype=np.float16)
empty_distances[:] = np.inf
sparse_distances = empty_distances.copy()
2016-12-17 14:46:15 +01:00
level_transfers = np.zeros(shape=(len(self.level_transfer_points),) * 2, dtype=np.int16)
level_transfers[:] = -1
for i, level in enumerate(self.levels.values()):
2016-12-21 13:31:56 +01:00
routers.update(level.build_routers(allowed_ctypes, allow_nonpublic, avoid, include))
2016-12-17 14:09:38 +01:00
router = routers[level]
level_distances = empty_distances.copy()
in_level_i = np.array(tuple(level.room_transfer_points.index(point)
for point in level.level_transfer_points), dtype=int)
in_graph_i = np.array(tuple(self.level_transfer_points.index(point)
for point in level.level_transfer_points), dtype=int)
level_distances[in_graph_i[:, None], in_graph_i] = router.shortest_paths[in_level_i[:, None], in_level_i]
better = level_distances < sparse_distances
sparse_distances[better] = level_distances[better]
level_transfers[better] = i
g_sparse = csgraph_from_dense(sparse_distances, null_value=np.inf)
shortest_paths, predecessors = shortest_path(g_sparse, return_predecessors=True)
2016-12-17 14:09:38 +01:00
2016-12-17 14:46:15 +01:00
routers[self] = GraphRouter(shortest_paths, predecessors, level_transfers)
2016-12-17 14:09:38 +01:00
return routers
def get_location_points(self, location: Location, mode):
2016-12-16 17:38:13 +01:00
if isinstance(location, PointLocation):
points = self.levels[location.level.name].connected_points(np.array((location.x, location.y)), mode)
2016-12-21 01:59:08 +01:00
if not points:
return (), None, None
points, distances, ctypes = zip(*((point, distance, ctype) for point, (distance, ctype) in points.items()))
distances = {points[i]: distance for i, distance in enumerate(distances)}
points = np.array(points, dtype=np.int)
return points, distances, ctypes
try:
if isinstance(location, AreaLocation):
points = self.levels[location.level.name].arealocation_points[location.name]
return points, None, None
elif isinstance(location, LocationGroup):
2016-12-23 22:52:14 +01:00
points = tuple(np.hstack(tuple(self.get_location_points(area, mode)[0]
for area in location.arealocations.all())).astype(np.int))
return points, None, None
except KeyError:
raise NotYetRoutable
2016-12-16 17:38:13 +01:00
def _get_points_by_i(self, points):
return tuple(self.points[i] for i in points)
2016-12-17 13:24:42 +01:00
def _allowed_points_index(self, points, allowed_points_i):
2016-12-16 17:38:13 +01:00
return np.array(tuple(i for i, point in enumerate(points) if point in allowed_points_i))
2016-12-24 01:41:32 +01:00
def get_route(self, origin: Location, destination: Location,
allowed_ctypes, allow_nonpublic, avoid, include, visible_nonpublic_areas=None):
orig_points_i, orig_distances, orig_ctypes = self.get_location_points(origin, 'orig')
dest_points_i, dest_distances, dest_ctypes = self.get_location_points(destination, 'dest')
2016-12-21 11:33:53 +01:00
if not len(orig_points_i) or not len(dest_points_i):
2016-12-21 01:59:08 +01:00
raise NoRouteFound()
if orig_distances is None and dest_distances is None:
if set(dest_points_i) & set(orig_points_i):
orig_points_i = tuple(set(orig_points_i) - set(dest_points_i))
if set(dest_points_i) & set(orig_points_i):
dest_points_i = tuple(set(dest_points_i) - set(orig_points_i))
if not len(orig_points_i) or not len(dest_points_i):
raise AlreadyThere()
2017-01-13 21:52:44 +01:00
# if set(orig_points_i) & set(dest_points_i):
# raise AlreadyThere()
add_orig_point = origin if isinstance(origin, PointLocation) else None
add_dest_point = destination if isinstance(destination, PointLocation) else None
2016-12-16 17:38:13 +01:00
orig_points = self._get_points_by_i(orig_points_i)
dest_points = self._get_points_by_i(dest_points_i)
2016-12-21 01:59:08 +01:00
common_points = tuple(set(orig_points) & set(dest_points))
2016-12-16 17:38:13 +01:00
2016-12-17 13:24:42 +01:00
best_route = NoRoute
2016-12-16 17:38:13 +01:00
# get routers
2016-12-21 13:31:56 +01:00
routers = self.build_routers(allowed_ctypes, allow_nonpublic, avoid, include)
2016-12-16 17:38:13 +01:00
# route within room
orig_rooms = set(point.room for point in orig_points)
dest_rooms = set(point.room for point in dest_points)
common_rooms = orig_rooms & dest_rooms
2016-12-21 01:59:08 +01:00
# rooms are directly connectable
if add_orig_point and add_dest_point and common_rooms:
room = tuple(common_rooms)[0]
ctype = room.check_connection((add_orig_point.x, add_orig_point.y), (add_dest_point.x, add_dest_point.y))
if ctype is not None:
from_point = GraphPoint(add_orig_point.x, add_orig_point.y, room)
to_point = GraphPoint(add_dest_point.x, add_dest_point.y, room)
return Route((GraphConnection(from_point, to_point, ctype=ctype), ))
2016-12-21 01:59:08 +01:00
if common_points:
# same location
if not add_orig_point and not add_dest_point:
raise AlreadyThere()
2016-12-21 01:59:08 +01:00
# points are connectable with only one via
best_point = None
best_distance = np.inf
for point in common_points:
distance = 0
if add_orig_point:
distance += abs(np.linalg.norm(add_orig_point.xy - point.xy))
if add_dest_point:
distance += abs(np.linalg.norm(add_dest_point.xy - point.xy))
if distance < best_distance:
best_distance = distance
best_point = point
connections = []
if add_orig_point:
from_point = GraphPoint(add_orig_point.x, add_orig_point.y, best_point.room)
ctype = orig_ctypes[tuple(orig_points_i).index(best_point.i)]
connections.append(GraphConnection(from_point, best_point, ctype=ctype))
if add_dest_point:
to_point = GraphPoint(add_dest_point.x, add_dest_point.y, best_point.room)
ctype = dest_ctypes[tuple(dest_points_i).index(best_point.i)]
connections.append(GraphConnection(best_point, to_point, ctype=ctype))
return Route(connections)
2016-12-16 17:38:13 +01:00
# get origin points for each room (points as point index within room)
2016-12-17 13:24:42 +01:00
orig_room_points = {room: self._allowed_points_index(room.points, orig_points_i) for room in orig_rooms}
dest_room_points = {room: self._allowed_points_index(room.points, dest_points_i) for room in dest_rooms}
2016-12-16 17:38:13 +01:00
# add distances to room routers
if orig_distances is not None:
for room in orig_rooms:
distances = np.array(tuple(orig_distances[room.points[i]] for i in orig_room_points[room]))
routers[room].shortest_paths[orig_room_points[room], :] += distances[:, None]
if dest_distances is not None:
for room in dest_rooms:
distances = np.array(tuple(dest_distances[room.points[i]] for i in dest_room_points[room]))
routers[room].shortest_paths[:, dest_room_points[room]] += distances
2016-12-16 17:38:13 +01:00
# if the points have common rooms, search for routes within those rooms
if common_rooms:
for room in common_rooms:
2016-12-17 14:09:38 +01:00
shortest_paths = routers[room].shortest_paths[orig_room_points[room][:, None],
dest_room_points[room]]
2016-12-16 17:38:13 +01:00
distance = shortest_paths.min()
# Is this route better than the previous ones?
2016-12-17 13:24:42 +01:00
if distance >= best_route.distance:
2016-12-16 17:38:13 +01:00
continue
# noinspection PyTypeChecker
2016-12-17 13:24:42 +01:00
from_point, to_point = np.argwhere(shortest_paths == distance)[0]
from_point = orig_room_points[room][from_point]
to_point = dest_room_points[room][to_point]
2016-12-17 14:09:38 +01:00
best_route = RoomRouteSegment(room, routers, from_point, to_point).as_route()
2016-12-16 17:38:13 +01:00
# get reachable room transfer points and their distance
2016-12-17 13:24:42 +01:00
# as a dictionary: global transfer point index => RoomRouteSegment
2016-12-17 14:09:38 +01:00
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')
2016-12-16 17:38:13 +01:00
# route within level
orig_levels = set(room.level for room in orig_rooms)
dest_levels = set(room.level for room in dest_rooms)
common_levels = orig_levels & dest_levels
# get reachable roomtransfer points for each level (points as room transfer point index within level)
2016-12-17 13:24:42 +01:00
orig_room_transfer_points = {level: self._allowed_points_index(level.room_transfer_points, orig_room_transfers)
for level in orig_levels}
dest_room_transfer_points = {level: self._allowed_points_index(level.room_transfer_points, dest_room_transfers)
for level in dest_levels}
2016-12-16 17:38:13 +01:00
2016-12-24 00:33:52 +01:00
# if the points have common levels, search for routes within those levels
2016-12-16 17:38:13 +01:00
if common_levels:
for level in common_levels:
2016-12-17 13:24:42 +01:00
o_points = orig_room_transfer_points[level]
d_points = dest_room_transfer_points[level]
2016-12-24 00:33:52 +01:00
if not len(o_points) or not len(d_points):
2016-12-24 00:33:52 +01:00
continue
2016-12-17 14:09:38 +01:00
shortest_paths = routers[level].shortest_paths[o_points[:, None], d_points]
2016-12-17 13:24:42 +01:00
# 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
2016-12-16 17:38:13 +01:00
for in_level_i in o_points))[:, None]
2016-12-17 13:24:42 +01:00
shortest_paths += np.array(tuple(dest_room_transfers[level.room_transfer_points[in_level_i]].distance
2016-12-16 17:38:13 +01:00
for in_level_i in d_points))
distance = shortest_paths.min()
# Is this route better than the previous ones?
2016-12-17 13:24:42 +01:00
if distance >= best_route.distance:
2016-12-16 17:38:13 +01:00
continue
# noinspection PyTypeChecker
2016-12-17 13:24:42 +01:00
from_point, to_point = np.argwhere(shortest_paths == distance)[0]
from_point = o_points[from_point]
to_point = d_points[to_point]
2016-12-17 14:46:15 +01:00
best_route = SegmentRoute((orig_room_transfers[level.room_transfer_points[from_point]],
LevelRouteSegment(level, routers, from_point, to_point),
dest_room_transfers[level.room_transfer_points[to_point]]),
distance=distance)
2016-12-17 13:24:42 +01:00
# get reachable level transfer points and their distance
# as a dictionary: global transfer point index => Route
2016-12-17 14:09:38 +01:00
orig_level_transfers = self._level_transfers(orig_levels, orig_room_transfers, routers, mode='orig')
dest_level_transfers = self._level_transfers(dest_levels, dest_room_transfers, routers, mode='dest')
2016-12-17 13:24:42 +01:00
# get reachable leveltransfer points (points as level transfer point index within graph)
2016-12-17 13:24:42 +01:00
orig_level_transfer_points = self._allowed_points_index(self.level_transfer_points, orig_level_transfers)
dest_level_transfer_points = self._allowed_points_index(self.level_transfer_points, dest_level_transfers)
# search a route within the whole graph
2016-12-24 00:33:52 +01:00
o_points = orig_level_transfer_points
d_points = dest_level_transfer_points
if len(o_points) and len(d_points):
2016-12-17 14:09:38 +01:00
shortest_paths = routers[self].shortest_paths[o_points[:, None], d_points]
2016-12-17 13:24:42 +01:00
# 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
for in_graph_i in o_points))[:, None]
shortest_paths += np.array(tuple(dest_level_transfers[self.level_transfer_points[in_graph_i]].distance
for in_graph_i in d_points))
distance = shortest_paths.min()
# Is this route better than the previous ones?
if distance < best_route.distance:
# noinspection PyTypeChecker
from_point, to_point = np.argwhere(shortest_paths == distance)[0]
from_point = o_points[from_point]
to_point = d_points[to_point]
2016-12-17 14:46:15 +01:00
best_route = SegmentRoute((orig_level_transfers[self.level_transfer_points[from_point]],
GraphRouteSegment(self, routers, from_point, to_point),
dest_level_transfers[self.level_transfer_points[to_point]]),
distance=distance)
2016-12-16 17:38:13 +01:00
2016-12-21 01:59:08 +01:00
if best_route is NoRoute:
raise NoRouteFound()
orig_ctype = orig_ctypes[tuple(orig_points_i).index(best_route.from_point)] if add_orig_point else None
dest_ctype = dest_ctypes[tuple(dest_points_i).index(best_route.to_point)] if add_dest_point else None
best_route = SegmentRouteWrapper(best_route, orig_point=add_orig_point, dest_point=add_dest_point,
orig_ctype=orig_ctype, dest_ctype=dest_ctype)
best_route = best_route.split()
return best_route
2016-12-16 17:38:13 +01:00
2016-12-17 14:09:38 +01:00
def _room_transfers(self, rooms, room_points, routers, mode):
2016-12-16 17:38:13 +01:00
if mode not in ('orig', 'dest'):
raise ValueError
room_transfers = {}
for room in rooms:
room_transfer_points = np.array(tuple(room.points.index(point)
for point in room.room_transfer_points), dtype=int)
2016-12-16 17:38:13 +01:00
points = room_points[room]
if mode == 'orig':
2016-12-17 14:09:38 +01:00
shortest_paths = routers[room].shortest_paths[points[:, None], room_transfer_points]
2016-12-16 17:38:13 +01:00
else:
2016-12-17 14:09:38 +01:00
shortest_paths = routers[room].shortest_paths[room_transfer_points[:, None], points]
2016-12-16 17:38:13 +01:00
# noinspection PyTypeChecker
for from_i, to_i in np.argwhere(shortest_paths != np.inf):
distance = shortest_paths[from_i, to_i]
2016-12-17 13:24:42 +01:00
from_i = points[from_i] if mode == 'orig' else room_transfer_points[from_i]
to_i = room_transfer_points[to_i] if mode == 'orig' else points[to_i]
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:
2016-12-17 14:09:38 +01:00
room_transfers[transfer_i] = RoomRouteSegment(room, routers, from_i, to_i)
2016-12-16 17:38:13 +01:00
return room_transfers
2016-12-17 14:09:38 +01:00
def _level_transfers(self, levels, all_room_transfers, routers, mode):
2016-12-17 13:24:42 +01:00
if mode not in ('orig', 'dest'):
raise ValueError
level_transfers = {}
for level in levels:
level_transfer_points = np.array(tuple(level.room_transfer_points.index(point)
for point in level.level_transfer_points), dtype=int)
2016-12-17 13:24:42 +01:00
points, distances = zip(*(tuple((level.room_transfer_points.index(point), segment.distance)
for point, segment in all_room_transfers.items()
if point in level.room_transfer_points)))
points = np.array(points)
distances = np.array(distances)
if mode == 'orig':
2016-12-17 14:09:38 +01:00
shortest_paths = routers[level].shortest_paths[points[:, None], level_transfer_points]
2016-12-17 13:24:42 +01:00
shortest_paths += distances[:, None]
else:
2016-12-17 14:09:38 +01:00
shortest_paths = routers[level].shortest_paths[level_transfer_points[:, None], points]
2016-12-17 13:24:42 +01:00
shortest_paths += distances
# noinspection PyTypeChecker
for from_i, to_i in np.argwhere(shortest_paths != np.inf):
distance = shortest_paths[from_i, to_i]
from_i = points[from_i] if mode == 'orig' else level_transfer_points[from_i]
to_i = level_transfer_points[to_i] if mode == 'orig' else points[to_i]
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:
2016-12-17 14:09:38 +01:00
segments = [LevelRouteSegment(level, routers, from_i, to_i)]
2016-12-17 13:24:42 +01:00
if mode == 'orig':
segments.insert(0, all_room_transfers[room_transfer_i])
else:
segments.append(all_room_transfers[room_transfer_i])
2016-12-17 14:46:15 +01:00
level_transfers[transfer_i] = SegmentRoute(segments, distance)
2016-12-17 13:24:42 +01:00
return level_transfers
def get_nearest_point(self, level, x, y):
return self.levels[level.name].nearest_point(np.array((x, y)), 'orig')
2016-12-17 14:46:15 +01:00
GraphRouter = namedtuple('GraphRouter', ('shortest_paths', 'predecessors', 'level_transfers', ))